diff options
author | David Mitchell <davem@iabyn.com> | 2011-03-21 14:14:52 +0000 |
---|---|---|
committer | David Mitchell <davem@iabyn.com> | 2011-03-21 14:30:20 +0000 |
commit | cd07c537987a76c934f141ca5bc0309e5a6b2609 (patch) | |
tree | e874b1968d5f287ff655a6517abeabff306926ab /pp_pack.c | |
parent | c34fab5fe3b5d2b8932d2f199a30b80c85950b75 (diff) | |
download | perl-cd07c537987a76c934f141ca5bc0309e5a6b2609.tar.gz |
pack test failures with long doubles on x86/gcc
[perl #86534]
When using 80-bit extended precision floats, gcc-generated code
can sometimes copy 10 bytes and sometimes 12. This can lead to 2 random
bytes something appearing in the output of pack('F') and pack('D').
Work around this by using sv_2nv() rather than SvNV()
(which expands to (SvNOK(sv) ? SvNVX(sv) : sv_2nv(sv) )
The basic issue is that the NV return value of a function is returned
in a floating point register, which is then written to memory as 10 bytes,
whereas a direct assignment, e.g. NV nv1 = nv2, is done by a 12-byte
memory copy.
However, when the sv_2nv() function is called as part of the ?:
expression, its returned value is written as *10* bytes to a temp location
on the stack, which is then copied as a *12* byte value to its final
destination, picking up 2 bytes of random data from the stack, which then
appears in the output of pack(), and ultimately leads to a test failure.
Diffstat (limited to 'pp_pack.c')
-rw-r--r-- | pp_pack.c | 10 |
1 files changed, 10 insertions, 0 deletions
@@ -3184,7 +3184,12 @@ extern const double _double_constants[]; Zero(&anv, 1, NV); /* can be long double with unused bits */ while (len-- > 0) { fromstr = NEXTFROM; +#ifdef __GNUC__ + /* to work round a gcc/x86 bug; don't use SvNV */ + anv.nv = sv_2nv(fromstr); +#else anv.nv = SvNV(fromstr); +#endif DO_BO_PACK_N(anv, NV); PUSH_BYTES(utf8, cur, anv.bytes, sizeof(anv.bytes)); } @@ -3197,7 +3202,12 @@ extern const double _double_constants[]; Zero(&aldouble, 1, long double); while (len-- > 0) { fromstr = NEXTFROM; +# ifdef __GNUC__ + /* to work round a gcc/x86 bug; don't use SvNV */ + aldouble.ld = (long double)sv_2nv(fromstr); +# else aldouble.ld = (long double)SvNV(fromstr); +# endif DO_BO_PACK_N(aldouble, long double); PUSH_BYTES(utf8, cur, aldouble.bytes, sizeof(aldouble.bytes)); } |