public inbox for newlib-cvs@sourceware.org
help / color / mirror / Atom feed
From: Corinna Vinschen <corinna@sourceware.org>
To: newlib-cvs@sourceware.org
Subject: [newlib-cygwin] strtod: Convert 64 bit double to 64 bit int during computation
Date: Mon, 09 Apr 2018 09:42:00 -0000	[thread overview]
Message-ID: <20180409094143.95676.qmail@sourceware.org> (raw)

https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=27652b608db73eec39208ec3078d7f3a06c3286d

commit 27652b608db73eec39208ec3078d7f3a06c3286d
Author: Corinna Vinschen <corinna@vinschen.de>
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 <corinna@vinschen.de>

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) {


                 reply	other threads:[~2018-04-09  9:42 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180409094143.95676.qmail@sourceware.org \
    --to=corinna@sourceware.org \
    --cc=newlib-cvs@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).