]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR 52428 Range checking when reading integer values.
authorJanne Blomqvist <jb@gcc.gnu.org>
Mon, 14 May 2012 19:39:23 +0000 (22:39 +0300)
committerJanne Blomqvist <jb@gcc.gnu.org>
Mon, 14 May 2012 19:39:23 +0000 (22:39 +0300)
gcc/fortran ChangeLog:

2012-05-14  Janne Blomqvist  <jb@gcc.gnu.org>

PR fortran/52428
* gfortran.texi: Update _gfortran_set_options documentation.
* invoke.texi: Remove runtime behavior description of
-fno-range-check.
* trans-decl.c (create_main_function): Don't pass the range-check
setting to the library.

libgfortran ChangeLog:

2012-05-14  Janne Blomqvist  <jb@gcc.gnu.org>

PR fortran/52428
* io/io.h (max_value): Rename to si_max, remove second argument.
* io/list_read.c (convert_integer): Use unsigned types when
parsing the digits, set max value depending on the sign.
* io/read.c (max_value): Rename to si_max, remove second argument,
simplify.
(read_decimal): Set max value depending on sign, always check
overflow.
(read_radix): Calculate max unsigned value directly.
* libgfortran.h (struct compile_options_t): Remove range_check
field.
* runtime/compile_options.c (set_options): Skip handling
options[7].
(init_compile_options): Don't set removed field.

gcc/testsuite ChangeLog:

2012-05-14  Janne Blomqvist  <jb@gcc.gnu.org>

PR fortran/52428
* gfortran.dg/int_range_io_1.f90: New test.

From-SVN: r187478

12 files changed:
gcc/fortran/ChangeLog
gcc/fortran/gfortran.texi
gcc/fortran/invoke.texi
gcc/fortran/trans-decl.c
gcc/testsuite/ChangeLog
gcc/testsuite/gfortran.dg/int_range_io_1.f90 [new file with mode: 0644]
libgfortran/ChangeLog
libgfortran/io/io.h
libgfortran/io/list_read.c
libgfortran/io/read.c
libgfortran/libgfortran.h
libgfortran/runtime/compile_options.c

index 5e1dba9343597ff9683344264a66ef8f94d8d39c..59cfa32297a5b372a1d9335de60613ce7fbddec7 100644 (file)
@@ -1,3 +1,12 @@
+2012-05-14  Janne Blomqvist  <jb@gcc.gnu.org>
+
+       PR fortran/52428
+       * gfortran.texi: Update _gfortran_set_options documentation.
+       * invoke.texi: Remove runtime behavior description of
+       -fno-range-check.
+       * trans-decl.c (create_main_function): Don't pass the range-check
+       setting to the library.
+
 2012-05-14  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/49110
index 96662c49423fb7205ee801a486138c67772ed941..ffcd3ece2d7d51815948974e185b68a585af319f 100644 (file)
@@ -2740,15 +2740,13 @@ Default: enabled.
 are (bitwise or-ed): GFC_RTCHECK_BOUNDS (1), GFC_RTCHECK_ARRAY_TEMPS (2),
 GFC_RTCHECK_RECURSION (4), GFC_RTCHECK_DO (16), GFC_RTCHECK_POINTER (32).
 Default: disabled.
-@item @var{option}[7] @tab If non zero, range checking is enabled.
-Default: enabled.  See -frange-check (@pxref{Code Gen Options}).
 @end multitable
 
 @item @emph{Example}:
 @smallexample
-  /* Use gfortran 4.7 default options.  */
-  static int options[] = @{68, 511, 0, 0, 1, 1, 0, 1@};
-  _gfortran_set_options (8, &options);
+  /* Use gfortran 4.8 default options.  */
+  static int options[] = @{68, 511, 0, 0, 1, 1, 0@};
+  _gfortran_set_options (7, &options);
 @end smallexample
 @end table
 
index 8db869bfa6843d56d70cac9b901c03c4fd846b94..658ed2375fc3d4f3e8f922b6d78df8fe2ddc30d3 100644 (file)
@@ -166,8 +166,7 @@ and warnings}.
 
 @item Runtime Options
 @xref{Runtime Options,,Options for influencing runtime behavior}.
-@gccoptlist{-fconvert=@var{conversion} -fmax-subrecord-length=@var{length}
--fno-range-check @gol
+@gccoptlist{-fconvert=@var{conversion} -fmax-subrecord-length=@var{length} @gol
 -frecord-marker=@var{length} -fsign-zero
 }
 
@@ -1116,16 +1115,6 @@ representation for unformatted files.
 The @code{CONVERT} specifier and the GFORTRAN_CONVERT_UNIT environment
 variable override the default specified by @option{-fconvert}.}
 
-
-@item -fno-range-check
-@opindex @code{fno-range-check}
-Disable range checking of input values during integer @code{READ} operations.
-For example, GNU Fortran will give an error if an input value is
-outside of the relevant range of [@code{-HUGE()}:@code{HUGE()}]. In other words,
-with @code{INTEGER (kind=4) :: i} , attempting to read @math{-2147483648} will
-give an error unless @option{-fno-range-check} is given. 
-
-
 @item -frecord-marker=@var{length}
 @opindex @code{frecord-marker=}@var{length}
 Specify the length of record markers for unformatted files.
index 1354ad05e3da1361ab4485019bd7341cee642ad5..0480f956c84f1cf01de81a3e61e84b946436f200 100644 (file)
@@ -5039,12 +5039,17 @@ create_main_function (tree fndecl)
                             build_int_cst (integer_type_node,
                                            (gfc_option.rtcheck
                                             & GFC_RTCHECK_BOUNDS)));
+    /* TODO: This is the -frange-check option, which no longer affects
+       library behavior; when bumping the library ABI this slot can be
+       reused for something else. As it is the last element in the
+       array, we can instead leave it out altogether.
     CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
                             build_int_cst (integer_type_node,
                                            gfc_option.flag_range_check));
+    */
 
     array_type = build_array_type (integer_type_node,
-                                  build_index_type (size_int (7)));
+                                  build_index_type (size_int (6)));
     array = build_constructor (array_type, v);
     TREE_CONSTANT (array) = 1;
     TREE_STATIC (array) = 1;
@@ -5059,7 +5064,7 @@ create_main_function (tree fndecl)
 
     tmp = build_call_expr_loc (input_location,
                           gfor_fndecl_set_options, 2,
-                          build_int_cst (integer_type_node, 8), var);
+                          build_int_cst (integer_type_node, 7), var);
     gfc_add_expr_to_block (&body, tmp);
   }
 
index c160fae15302e99347d8f33b112c7479cb796471..d6a2adfe77d8ceeb804f267d53a83bfff46effa0 100644 (file)
@@ -1,3 +1,8 @@
+2012-05-14  Janne Blomqvist  <jb@gcc.gnu.org>
+
+       PR fortran/52428
+       * gfortran.dg/int_range_io_1.f90: New test.
+
 2012-05-14  Andi Kleen <ak@linux.intel.com>
            Jakub Jelinek  <jakub@redhat.com>
 
diff --git a/gcc/testsuite/gfortran.dg/int_range_io_1.f90 b/gcc/testsuite/gfortran.dg/int_range_io_1.f90
new file mode 100644 (file)
index 0000000..de1fdb8
--- /dev/null
@@ -0,0 +1,34 @@
+! { dg-do run }
+! { dg-options "-fno-range-check" }
+! PR 52428 Read IO of integers near the end of range. Note that we
+! support the two's complement representation even though the Fortran
+! numerical model has a symmetric range.  (The -fno-range-check option
+! is needed to allow the -2147483648 literal.)
+program int_range
+  implicit none
+  character(25) :: inputline = "-2147483648"
+  integer(4) ::  test
+  integer :: st
+
+  read(inputline,100) test
+100 format(1i11)
+  if (test /= -2147483648) call abort
+  inputline(1:1) = " "
+  read(inputline, 100, iostat=st) test
+  if (st == 0) call abort
+  inputline(11:11) = "7"
+  read(inputline, 100) test
+  if (test /= 2147483647) call abort
+
+  ! Same as above but with list-formatted IO
+  inputline = "-2147483648"
+  read(inputline, *) test
+  if (test /= -2147483648) call abort
+  inputline(1:1) = " "
+  read(inputline, *, iostat=st) test
+  if (st == 0) call abort
+  inputline(11:11) = "7"
+  read(inputline, *) test
+  if (test /= 2147483647) call abort
+
+end program int_range
index a6223fc24c3d644aa5bc72dd38504d4bb48c5b93..088d51786d727a13a2147526ec6cf764442afdcc 100644 (file)
@@ -1,3 +1,20 @@
+2012-05-14  Janne Blomqvist  <jb@gcc.gnu.org>
+
+       PR fortran/52428
+       * io/io.h (max_value): Rename to si_max, remove second argument.
+       * io/list_read.c (convert_integer): Use unsigned types when
+       parsing the digits, set max value depending on the sign.
+       * io/read.c (max_value): Rename to si_max, remove second argument,
+       simplify.
+       (read_decimal): Set max value depending on sign, always check
+       overflow.
+       (read_radix): Calculate max unsigned value directly.
+       * libgfortran.h (struct compile_options_t): Remove range_check
+       field.
+       * runtime/compile_options.c (set_options): Skip handling
+       options[7].
+       (init_compile_options): Don't set removed field.
+
 2012-05-11  Tobias Burnus  <burnus@net-b.de>
 
        PR fortran/53310
index 06364e17b2ca9a6d4e8356801fd6011f41d84048..6b54af18362414bcae7df430086ccb66fe2a5e19 100644 (file)
@@ -661,8 +661,8 @@ internal_proto(hit_eof);
 extern void set_integer (void *, GFC_INTEGER_LARGEST, int);
 internal_proto(set_integer);
 
-extern GFC_UINTEGER_LARGEST max_value (int, int);
-internal_proto(max_value);
+extern GFC_UINTEGER_LARGEST si_max (int);
+internal_proto(si_max);
 
 extern int convert_real (st_parameter_dt *, void *, const char *, int);
 internal_proto(convert_real);
index 4d2ce79412014a231cc8fe2fc190d2acead8e3dc..b0c4e5fca52823d1a3268c9ac3e70b7634cddf2c 100644 (file)
@@ -461,12 +461,20 @@ convert_integer (st_parameter_dt *dtp, int length, int negative)
 {
   char c, *buffer, message[MSGLEN];
   int m;
-  GFC_INTEGER_LARGEST v, max, max10;
+  GFC_UINTEGER_LARGEST v, max, max10;
+  GFC_INTEGER_LARGEST value;
 
   buffer = dtp->u.p.saved_string;
   v = 0;
 
-  max = (length == -1) ? MAX_REPEAT : max_value (length, 1);
+  if (length == -1)
+    max = MAX_REPEAT;
+  else
+    {
+      max = si_max (length);
+      if (negative)
+       max++;
+    }
   max10 = max / 10;
 
   for (;;)
@@ -490,8 +498,10 @@ convert_integer (st_parameter_dt *dtp, int length, int negative)
   if (length != -1)
     {
       if (negative)
-       v = -v;
-      set_integer (dtp->u.p.value, v, length);
+       value = -v;
+      else
+       value = v;
+      set_integer (dtp->u.p.value, value, length);
     }
   else
     {
index 32c8b3250f8efc7d7a377ca1e263cec606166c70..c493d5a5f43e886bfbb640f1636dfa5eeea8611c 100644 (file)
@@ -87,46 +87,34 @@ set_integer (void *dest, GFC_INTEGER_LARGEST value, int length)
 }
 
 
-/* max_value()-- Given a length (kind), return the maximum signed or
- * unsigned value */
+/* Max signed value of size give by length argument.  */
 
 GFC_UINTEGER_LARGEST
-max_value (int length, int signed_flag)
+si_max (int length)
 {
   GFC_UINTEGER_LARGEST value;
-#if defined HAVE_GFC_REAL_16 || defined HAVE_GFC_REAL_10
-  int n;
-#endif
 
   switch (length)
-    {
+      {
 #if defined HAVE_GFC_REAL_16 || defined HAVE_GFC_REAL_10
     case 16:
     case 10:
       value = 1;
-      for (n = 1; n < 4 * length; n++)
+      for (int n = 1; n < 4 * length; n++)
         value = (value << 2) + 3;
-      if (! signed_flag)
-        value = 2*value+1;
-      break;
+      return value;
 #endif
     case 8:
-      value = signed_flag ? 0x7fffffffffffffff : 0xffffffffffffffff;
-      break;
+      return GFC_INTEGER_8_HUGE;
     case 4:
-      value = signed_flag ? 0x7fffffff : 0xffffffff;
-      break;
+      return GFC_INTEGER_4_HUGE;
     case 2:
-      value = signed_flag ? 0x7fff : 0xffff;
-      break;
+      return GFC_INTEGER_2_HUGE;
     case 1:
-      value = signed_flag ? 0x7f : 0xff;
-      break;
+      return GFC_INTEGER_1_HUGE;
     default:
       internal_error (NULL, "Bad integer kind");
     }
-
-  return value;
 }
 
 
@@ -634,11 +622,7 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
       return;
     }
 
-  maxv = max_value (length, 1);
-  maxv_10 = maxv / 10;
-
   negative = 0;
-  value = 0;
 
   switch (*p)
     {
@@ -656,6 +640,11 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
       break;
     }
 
+  maxv = si_max (length);
+  if (negative)
+    maxv++;
+  maxv_10 = maxv / 10;
+
   /* At this point we have a digit-string */
   value = 0;
 
@@ -674,20 +663,21 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
       if (c < '0' || c > '9')
        goto bad;
 
-      if (value > maxv_10 && compile_options.range_check == 1)
+      if (value > maxv_10)
        goto overflow;
 
       c -= '0';
       value = 10 * value;
 
-      if (value > maxv - c && compile_options.range_check == 1)
+      if (value > maxv - c)
        goto overflow;
       value += c;
     }
 
-  v = value;
   if (negative)
-    v = -v;
+    v = -value;
+  else
+    v = value;
 
   set_integer (dest, v, length);
   return;
@@ -734,7 +724,8 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length,
       return;
     }
 
-  maxv = max_value (length, 0);
+  /* Maximum unsigned value, assuming two's complement.  */
+  maxv = 2 * si_max (length) + 1;
   maxv_r = maxv / radix;
 
   negative = 0;
index 051e2e85a1eceb6f2a8856f401c1e9d5faecb557..7dafd940e62cd29a856d70415777f1d45331af7c 100644 (file)
@@ -535,7 +535,6 @@ typedef struct
   size_t record_marker;
   int max_subrecord_length;
   int bounds_check;
-  int range_check;
 }
 compile_options_t;
 
index 0e657f73ba64a243373baf0ccfc2fa39b2b43777..2ba1aedf5c5a1d56dcd2a7ac2fa716247c6da26d 100644 (file)
@@ -169,8 +169,10 @@ set_options (int num, int options[])
     compile_options.sign_zero = options[5];
   if (num >= 7)
     compile_options.bounds_check = options[6];
-  if (num >= 8)
-    compile_options.range_check = options[7];
+  /* options[7] is the -frange-check option, which no longer affects
+     the library behavior; range checking is now always done when
+     parsing integers. It's place in the options array is retained due
+     to ABI compatibility. Remove when bumping the library ABI.  */
 
   /* If backtrace is required, we set signal handlers on the POSIX
      2001 signals with core action.  */
@@ -223,7 +225,6 @@ init_compile_options (void)
   compile_options.pedantic = 0;
   compile_options.backtrace = 0;
   compile_options.sign_zero = 1;
-  compile_options.range_check = 1;
 }
 
 /* Function called by the front-end to tell us the