This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Patch, libfortran] PR 19155 Parsing invalid floating point input and EINVAL


Hi,

Steve Ellcey reported that gfortran.dg/pr19155.f fails on HP-UX 11.31
because on that target strtod sets errno to EINVAL for invalid input,
whereas many other implementations such as glibc does not.

The problem is that C99 says nothing about setting errno to EINVAL for
invalid input, and POSIX merely says that "errno may be set to
[EINVAL]."

http://pubs.opengroup.org/onlinepubs/9699919799/functions/strtod.html

Therefore the portable way of checking for bad input is to check
whether endptr == nptr instead of checking whether errno == EINVAL.
The attached patch does this. In order to support the extension of
parsing an input of style "E+NN" as 0, the patch fixes the string
passed to strtod. This is done only when using an edit descriptor, not
for list input, as with list input there's IMHO a bigger chance we
accidentally parse the wrong thing if we accept stuff like this.

Regtested on x86_64-unknown-linux-gnu, Ok for trunk?

2011-05-28  Janne Blomqvist  <jb@gcc.gnu.org>

	PR libfortran/19155
	* io/read.c (convert_real): Check for invalid input by comparing
	endptr instead of EINVAL.
	(read_f): Fixup floating point input without significand.


-- 
Janne Blomqvist
diff --git a/libgcc/configure b/libgcc/configure
old mode 100644
new mode 100755
diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c
index 3ee5717..d07d09d 100644
--- a/libgfortran/io/read.c
+++ b/libgfortran/io/read.c
@@ -131,45 +131,45 @@ max_value (int length, int signed_flag)
 
 
 /* convert_real()-- Convert a character representation of a floating
-   point number to the machine number.  Returns nonzero if there is a
-   range problem during conversion.  Note: many architectures
-   (e.g. IA-64, HP-PA) require that the storage pointed to by the dest
-   argument is properly aligned for the type in question.  */
+   point number to the machine number.  Returns nonzero if there is an
+   invalid input.  Note: many architectures (e.g. IA-64, HP-PA)
+   require that the storage pointed to by the dest argument is
+   properly aligned for the type in question.  */
 
 int
 convert_real (st_parameter_dt *dtp, void *dest, const char *buffer, int length)
 {
-  errno = 0;
+  char *endptr = NULL;
 
   switch (length)
     {
     case 4:
       *((GFC_REAL_4*) dest) =
 #if defined(HAVE_STRTOF)
-	gfc_strtof (buffer, NULL);
+	gfc_strtof (buffer, &endptr);
 #else
-	(GFC_REAL_4) gfc_strtod (buffer, NULL);
+	(GFC_REAL_4) gfc_strtod (buffer, &endptr);
 #endif
       break;
 
     case 8:
-      *((GFC_REAL_8*) dest) = gfc_strtod (buffer, NULL);
+      *((GFC_REAL_8*) dest) = gfc_strtod (buffer, &endptr);
       break;
 
 #if defined(HAVE_GFC_REAL_10) && defined (HAVE_STRTOLD)
     case 10:
-      *((GFC_REAL_10*) dest) = gfc_strtold (buffer, NULL);
+      *((GFC_REAL_10*) dest) = gfc_strtold (buffer, &endptr);
       break;
 #endif
 
 #if defined(HAVE_GFC_REAL_16)
 # if defined(GFC_REAL_16_IS_FLOAT128)
     case 16:
-      *((GFC_REAL_16*) dest) = __qmath_(strtoflt128) (buffer, NULL);
+      *((GFC_REAL_16*) dest) = __qmath_(strtoflt128) (buffer, &endptr);
       break;
 # elif defined(HAVE_STRTOLD)
     case 16:
-      *((GFC_REAL_16*) dest) = gfc_strtold (buffer, NULL);
+      *((GFC_REAL_16*) dest) = gfc_strtold (buffer, &endptr);
       break;
 # endif
 #endif
@@ -178,10 +178,10 @@ convert_real (st_parameter_dt *dtp, void *dest, const char *buffer, int length)
       internal_error (&dtp->common, "Unsupported real kind during IO");
     }
 
-  if (errno == EINVAL)
+  if (buffer == endptr)
     {
       generate_error (&dtp->common, LIBERROR_READ_VALUE,
-		      "Error during floating point read");
+  		      "Error during floating point read");
       next_record (dtp, 1);
       return 1;
     }
@@ -1114,6 +1114,14 @@ done:
   /* Output a trailing '0' after decimal point if not yet found.  */
   if (seen_dp && !seen_dec_digit)
     *(out++) = '0';
+  /* Handle input of style "E+NN" by inserting a 0 for the
+     significand.  */
+  else if (!seen_int_digit && !seen_dec_digit)
+    {
+      notify_std (&dtp->common, GFC_STD_LEGACY, 
+		  "REAL input of style 'E+NN'");
+      *(out++) = '0';
+    }
 
   /* Print out the exponent to finish the reformatted number.  Maximum 4
      digits for the exponent.  */

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]