PR 52428 Range checking when reading integer values.

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
This commit is contained in:
Janne Blomqvist 2012-05-14 22:39:23 +03:00
parent f62866740b
commit 80b91c0b39
12 changed files with 117 additions and 59 deletions

View 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> 2012-05-14 Tobias Burnus <burnus@net-b.de>
PR fortran/49110 PR fortran/49110

View File

@ -2740,15 +2740,13 @@ Default: enabled.
are (bitwise or-ed): GFC_RTCHECK_BOUNDS (1), GFC_RTCHECK_ARRAY_TEMPS (2), 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). GFC_RTCHECK_RECURSION (4), GFC_RTCHECK_DO (16), GFC_RTCHECK_POINTER (32).
Default: disabled. 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 @end multitable
@item @emph{Example}: @item @emph{Example}:
@smallexample @smallexample
/* Use gfortran 4.7 default options. */ /* Use gfortran 4.8 default options. */
static int options[] = @{68, 511, 0, 0, 1, 1, 0, 1@}; static int options[] = @{68, 511, 0, 0, 1, 1, 0@};
_gfortran_set_options (8, &options); _gfortran_set_options (7, &options);
@end smallexample @end smallexample
@end table @end table

View File

@ -166,8 +166,7 @@ and warnings}.
@item Runtime Options @item Runtime Options
@xref{Runtime Options,,Options for influencing runtime behavior}. @xref{Runtime Options,,Options for influencing runtime behavior}.
@gccoptlist{-fconvert=@var{conversion} -fmax-subrecord-length=@var{length} @gccoptlist{-fconvert=@var{conversion} -fmax-subrecord-length=@var{length} @gol
-fno-range-check @gol
-frecord-marker=@var{length} -fsign-zero -frecord-marker=@var{length} -fsign-zero
} }
@ -1116,16 +1115,6 @@ representation for unformatted files.
The @code{CONVERT} specifier and the GFORTRAN_CONVERT_UNIT environment The @code{CONVERT} specifier and the GFORTRAN_CONVERT_UNIT environment
variable override the default specified by @option{-fconvert}.} 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} @item -frecord-marker=@var{length}
@opindex @code{frecord-marker=}@var{length} @opindex @code{frecord-marker=}@var{length}
Specify the length of record markers for unformatted files. Specify the length of record markers for unformatted files.

View File

@ -5039,12 +5039,17 @@ create_main_function (tree fndecl)
build_int_cst (integer_type_node, build_int_cst (integer_type_node,
(gfc_option.rtcheck (gfc_option.rtcheck
& GFC_RTCHECK_BOUNDS))); & 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, CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
build_int_cst (integer_type_node, build_int_cst (integer_type_node,
gfc_option.flag_range_check)); gfc_option.flag_range_check));
*/
array_type = build_array_type (integer_type_node, 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); array = build_constructor (array_type, v);
TREE_CONSTANT (array) = 1; TREE_CONSTANT (array) = 1;
TREE_STATIC (array) = 1; TREE_STATIC (array) = 1;
@ -5059,7 +5064,7 @@ create_main_function (tree fndecl)
tmp = build_call_expr_loc (input_location, tmp = build_call_expr_loc (input_location,
gfor_fndecl_set_options, 2, 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); gfc_add_expr_to_block (&body, tmp);
} }

View 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> 2012-05-14 Andi Kleen <ak@linux.intel.com>
Jakub Jelinek <jakub@redhat.com> Jakub Jelinek <jakub@redhat.com>

View File

@ -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

View 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> 2012-05-11 Tobias Burnus <burnus@net-b.de>
PR fortran/53310 PR fortran/53310

View File

@ -661,8 +661,8 @@ internal_proto(hit_eof);
extern void set_integer (void *, GFC_INTEGER_LARGEST, int); extern void set_integer (void *, GFC_INTEGER_LARGEST, int);
internal_proto(set_integer); internal_proto(set_integer);
extern GFC_UINTEGER_LARGEST max_value (int, int); extern GFC_UINTEGER_LARGEST si_max (int);
internal_proto(max_value); internal_proto(si_max);
extern int convert_real (st_parameter_dt *, void *, const char *, int); extern int convert_real (st_parameter_dt *, void *, const char *, int);
internal_proto(convert_real); internal_proto(convert_real);

View File

@ -461,12 +461,20 @@ convert_integer (st_parameter_dt *dtp, int length, int negative)
{ {
char c, *buffer, message[MSGLEN]; char c, *buffer, message[MSGLEN];
int m; int m;
GFC_INTEGER_LARGEST v, max, max10; GFC_UINTEGER_LARGEST v, max, max10;
GFC_INTEGER_LARGEST value;
buffer = dtp->u.p.saved_string; buffer = dtp->u.p.saved_string;
v = 0; 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; max10 = max / 10;
for (;;) for (;;)
@ -490,8 +498,10 @@ convert_integer (st_parameter_dt *dtp, int length, int negative)
if (length != -1) if (length != -1)
{ {
if (negative) if (negative)
v = -v; value = -v;
set_integer (dtp->u.p.value, v, length); else
value = v;
set_integer (dtp->u.p.value, value, length);
} }
else else
{ {

View 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 /* Max signed value of size give by length argument. */
* unsigned value */
GFC_UINTEGER_LARGEST GFC_UINTEGER_LARGEST
max_value (int length, int signed_flag) si_max (int length)
{ {
GFC_UINTEGER_LARGEST value; GFC_UINTEGER_LARGEST value;
#if defined HAVE_GFC_REAL_16 || defined HAVE_GFC_REAL_10
int n;
#endif
switch (length) switch (length)
{ {
#if defined HAVE_GFC_REAL_16 || defined HAVE_GFC_REAL_10 #if defined HAVE_GFC_REAL_16 || defined HAVE_GFC_REAL_10
case 16: case 16:
case 10: case 10:
value = 1; value = 1;
for (n = 1; n < 4 * length; n++) for (int n = 1; n < 4 * length; n++)
value = (value << 2) + 3; value = (value << 2) + 3;
if (! signed_flag) return value;
value = 2*value+1;
break;
#endif #endif
case 8: case 8:
value = signed_flag ? 0x7fffffffffffffff : 0xffffffffffffffff; return GFC_INTEGER_8_HUGE;
break;
case 4: case 4:
value = signed_flag ? 0x7fffffff : 0xffffffff; return GFC_INTEGER_4_HUGE;
break;
case 2: case 2:
value = signed_flag ? 0x7fff : 0xffff; return GFC_INTEGER_2_HUGE;
break;
case 1: case 1:
value = signed_flag ? 0x7f : 0xff; return GFC_INTEGER_1_HUGE;
break;
default: default:
internal_error (NULL, "Bad integer kind"); 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; return;
} }
maxv = max_value (length, 1);
maxv_10 = maxv / 10;
negative = 0; negative = 0;
value = 0;
switch (*p) switch (*p)
{ {
@ -656,6 +640,11 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
break; break;
} }
maxv = si_max (length);
if (negative)
maxv++;
maxv_10 = maxv / 10;
/* At this point we have a digit-string */ /* At this point we have a digit-string */
value = 0; value = 0;
@ -674,20 +663,21 @@ read_decimal (st_parameter_dt *dtp, const fnode *f, char *dest, int length)
if (c < '0' || c > '9') if (c < '0' || c > '9')
goto bad; goto bad;
if (value > maxv_10 && compile_options.range_check == 1) if (value > maxv_10)
goto overflow; goto overflow;
c -= '0'; c -= '0';
value = 10 * value; value = 10 * value;
if (value > maxv - c && compile_options.range_check == 1) if (value > maxv - c)
goto overflow; goto overflow;
value += c; value += c;
} }
v = value;
if (negative) if (negative)
v = -v; v = -value;
else
v = value;
set_integer (dest, v, length); set_integer (dest, v, length);
return; return;
@ -734,7 +724,8 @@ read_radix (st_parameter_dt *dtp, const fnode *f, char *dest, int length,
return; return;
} }
maxv = max_value (length, 0); /* Maximum unsigned value, assuming two's complement. */
maxv = 2 * si_max (length) + 1;
maxv_r = maxv / radix; maxv_r = maxv / radix;
negative = 0; negative = 0;

View File

@ -535,7 +535,6 @@ typedef struct
size_t record_marker; size_t record_marker;
int max_subrecord_length; int max_subrecord_length;
int bounds_check; int bounds_check;
int range_check;
} }
compile_options_t; compile_options_t;

View File

@ -169,8 +169,10 @@ set_options (int num, int options[])
compile_options.sign_zero = options[5]; compile_options.sign_zero = options[5];
if (num >= 7) if (num >= 7)
compile_options.bounds_check = options[6]; compile_options.bounds_check = options[6];
if (num >= 8) /* options[7] is the -frange-check option, which no longer affects
compile_options.range_check = options[7]; 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 /* If backtrace is required, we set signal handlers on the POSIX
2001 signals with core action. */ 2001 signals with core action. */
@ -223,7 +225,6 @@ init_compile_options (void)
compile_options.pedantic = 0; compile_options.pedantic = 0;
compile_options.backtrace = 0; compile_options.backtrace = 0;
compile_options.sign_zero = 1; compile_options.sign_zero = 1;
compile_options.range_check = 1;
} }
/* Function called by the front-end to tell us the /* Function called by the front-end to tell us the