From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 99364 invoked by alias); 9 Apr 2018 09:42:24 -0000 Mailing-List: contact newlib-cvs-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: newlib-cvs-owner@sourceware.org Received: (qmail 95679 invoked by uid 9078); 9 Apr 2018 09:41:43 -0000 Date: Mon, 09 Apr 2018 09:42:00 -0000 Message-ID: <20180409094143.95676.qmail@sourceware.org> Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Corinna Vinschen To: newlib-cvs@sourceware.org Subject: [newlib-cygwin] strtod: Convert 64 bit double to 64 bit int during computation X-Act-Checkin: newlib-cygwin X-Git-Author: Corinna Vinschen X-Git-Refname: refs/heads/master X-Git-Oldrev: 1ee6654e5058038cd97e93d7a1e3c4337820eb9d X-Git-Newrev: 27652b608db73eec39208ec3078d7f3a06c3286d X-SW-Source: 2018-q2/txt/msg00000.txt.bz2 https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=27652b608db73eec39208ec3078d7f3a06c3286d commit 27652b608db73eec39208ec3078d7f3a06c3286d Author: Corinna Vinschen Date: Mon Apr 9 11:31:04 2018 +0200 strtod: Convert 64 bit double to 64 bit int during computation The gdtoa implementation uses the type long, defined as Long, in lots of code. For historical reason newlib defines Long as int32_t instead. This works fine, as long as floating point exceptions are not enabled. The conversion to 32 bit int can lead to a FE_INVALID situation. Example: const char *str = "121645100408832000.0"; char *ptr; feenableexcept (FE_INVALID); strtod (str, &ptr); This leads to the following situation in strtod double aadj; Long L; [...] L = (Long)aadj; For instance, on x86_64 the code here is cvttsd2si %xmm0,%eax At this point, aadj is 2529648000.0 in our example. The conversion to 32 bit %eax results in a negative int value, thus the conversion is invalid. With feenableexcept (FE_INVALID), a SIGFPE is raised. Fix this by always using 64 bit ints here if double is not a 32 bit type to avoid this type of FP exceptions. Signed-off-by: Corinna Vinschen Diff: --- newlib/libc/stdlib/strtod.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/newlib/libc/stdlib/strtod.c b/newlib/libc/stdlib/strtod.c index 402510c..0cfa9e6 100644 --- a/newlib/libc/stdlib/strtod.c +++ b/newlib/libc/stdlib/strtod.c @@ -1186,7 +1186,16 @@ _strtod_l (struct _reent *ptr, const char *__restrict s00, char **__restrict se, #endif if (y == z) { /* Can we stop now? */ +#ifndef _DOUBLE_IS_32BITS + /* If FE_INVALID floating point exceptions are + enabled, a conversion to a 32 bit value is + dangerous. A positive double value can result + in a negative 32 bit int, thus raising SIGFPE. + To avoid this, always convert into 64 bit here. */ + __int64_t L = (__int64_t)aadj; +#else L = (Long)aadj; +#endif aadj -= L; /* The tolerances below are conservative. */ if (dsign || dword1(rv) || dword0(rv) & Bndry_mask) {