diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-09-28 08:57:29 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-09-28 08:57:29 +0000 |
commit | bc4f7cabbe20fbc3ca6bff0daaca1dcba4bc72ac (patch) | |
tree | 8bf6cc290e95f91d4d1477879cbd7fa7e6aaeff1 | |
parent | 923263dddd270bd3efb79b83c0bea924593747fe (diff) | |
download | src-bc4f7cabbe20fbc3ca6bff0daaca1dcba4bc72ac.tar.gz src-bc4f7cabbe20fbc3ca6bff0daaca1dcba4bc72ac.zip |
MFC r352710:
Do not left-shift a negative number (inducing undefined behavior in
C/C++) in exp(3), expf(3), expm1(3) and expm1f(3) during intermediate
computations that compute the IEEE-754 bit pattern for |2**k| for
integer |k|.
The implementations of exp(3), expf(3), expm1(3) and expm1f(3) need to
compute IEEE-754 bit patterns for 2**k in certain places. (k is an
integer and 2**k is exactly representable in IEEE-754.)
Currently they do things like 0x3FF0'0000+(k<<20), which is to say they
take the bit pattern representing 1 and then add directly to the
exponent field to get the desired power of two. This is fine when k is
non-negative.
But when k<0 (and certain classes of input trigger this), this
left-shifts a negative number -- an operation with undefined behavior in
C and C++.
The desired semantics can be achieved by instead adding the
possibly-negative k to the IEEE-754 exponent bias to get the desired
exponent field, _then_ shifting that into its proper overall position.
(Note that in case of s_expm1.c and s_expm1f.c, there are SET_HIGH_WORD
and SET_FLOAT_WORD uses further down in each of these files that perform
shift operations involving k, but by these points k's range has been
restricted to 2 < k <= 56, and the shift operations under those
circumstances can't do anything that would be UB.)
Submitted by: Jeff Walden, https://github.com/jswalden
Obtained from: https://github.com/freebsd/freebsd/pull/411
Obtained from: https://github.com/freebsd/freebsd/pull/412
Notes
Notes:
svn path=/stable/8/; revision=352835
-rw-r--r-- | lib/msun/src/e_exp.c | 4 | ||||
-rw-r--r-- | lib/msun/src/e_expf.c | 4 | ||||
-rw-r--r-- | lib/msun/src/s_expm1.c | 2 | ||||
-rw-r--r-- | lib/msun/src/s_expm1f.c | 2 |
4 files changed, 6 insertions, 6 deletions
diff --git a/lib/msun/src/e_exp.c b/lib/msun/src/e_exp.c index 5b9a10c1a3d6..5403e3756e0c 100644 --- a/lib/msun/src/e_exp.c +++ b/lib/msun/src/e_exp.c @@ -143,9 +143,9 @@ __ieee754_exp(double x) /* default IEEE double exp */ /* x is now in primary range */ t = x*x; if(k >= -1021) - INSERT_WORDS(twopk,0x3ff00000+(k<<20), 0); + INSERT_WORDS(twopk,((u_int32_t)(0x3ff+k))<<20, 0); else - INSERT_WORDS(twopk,0x3ff00000+((k+1000)<<20), 0); + INSERT_WORDS(twopk,((u_int32_t)(0x3ff+(k+1000)))<<20, 0); c = x - t*(P1+t*(P2+t*(P3+t*(P4+t*P5)))); if(k==0) return one-((x*c)/(c-2.0)-x); else y = one-((lo-(x*c)/(2.0-c))-hi); diff --git a/lib/msun/src/e_expf.c b/lib/msun/src/e_expf.c index 5f4649244f77..f554fd6cdee7 100644 --- a/lib/msun/src/e_expf.c +++ b/lib/msun/src/e_expf.c @@ -80,9 +80,9 @@ __ieee754_expf(float x) /* default IEEE double exp */ /* x is now in primary range */ t = x*x; if(k >= -125) - SET_FLOAT_WORD(twopk,0x3f800000+(k<<23)); + SET_FLOAT_WORD(twopk,((u_int32_t)(0x7f+k))<<23); else - SET_FLOAT_WORD(twopk,0x3f800000+((k+100)<<23)); + SET_FLOAT_WORD(twopk,((u_int32_t)(0x7f+(k+100)))<<23); c = x - t*(P1+t*P2); if(k==0) return one-((x*c)/(c-(float)2.0)-x); else y = one-((lo-(x*c)/((float)2.0-c))-hi); diff --git a/lib/msun/src/s_expm1.c b/lib/msun/src/s_expm1.c index 3de7bfbc837a..2a030b29c7f4 100644 --- a/lib/msun/src/s_expm1.c +++ b/lib/msun/src/s_expm1.c @@ -186,7 +186,7 @@ expm1(double x) e = hxs*((r1-t)/(6.0 - x*t)); if(k==0) return x - (x*e-hxs); /* c is 0 */ else { - INSERT_WORDS(twopk,0x3ff00000+(k<<20),0); /* 2^k */ + INSERT_WORDS(twopk,((u_int32_t)(0x3ff+k))<<20,0); /* 2^k */ e = (x*(e-c)-c); e -= hxs; if(k== -1) return 0.5*(x-e)-0.5; diff --git a/lib/msun/src/s_expm1f.c b/lib/msun/src/s_expm1f.c index 483472ce69b8..da8f49ddec08 100644 --- a/lib/msun/src/s_expm1f.c +++ b/lib/msun/src/s_expm1f.c @@ -92,7 +92,7 @@ expm1f(float x) e = hxs*((r1-t)/((float)6.0 - x*t)); if(k==0) return x - (x*e-hxs); /* c is 0 */ else { - SET_FLOAT_WORD(twopk,0x3f800000+(k<<23)); /* 2^k */ + SET_FLOAT_WORD(twopk,((u_int32_t)(0x7f+k))<<23); /* 2^k */ e = (x*(e-c)-c); e -= hxs; if(k== -1) return (float)0.5*(x-e)-(float)0.5; |