summaryrefslogtreecommitdiff
path: root/libgfortran
diff options
context:
space:
mode:
authorjb <jb@138bc75d-0d04-0410-961f-82ee72b054a4>2012-05-14 19:39:23 +0000
committerjb <jb@138bc75d-0d04-0410-961f-82ee72b054a4>2012-05-14 19:39:23 +0000
commit7f4f15dc761b8c76f3945354b6069daa7c63b4a8 (patch)
tree1b4a3a8d4b65ec8d0a88de4f00b90d28ce493090 /libgfortran
parent5dc7473db4e0ec618caae0858c1ccbb395b06213 (diff)
downloadgcc-7f4f15dc761b8c76f3945354b6069daa7c63b4a8.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@187478 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgfortran')
-rw-r--r--libgfortran/ChangeLog17
-rw-r--r--libgfortran/io/io.h4
-rw-r--r--libgfortran/io/list_read.c18
-rw-r--r--libgfortran/io/read.c51
-rw-r--r--libgfortran/libgfortran.h1
-rw-r--r--libgfortran/runtime/compile_options.c7
6 files changed, 58 insertions, 40 deletions
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index a6223fc24c3..088d51786d7 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -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
diff --git a/libgfortran/io/io.h b/libgfortran/io/io.h
index 06364e17b2c..6b54af18362 100644
--- a/libgfortran/io/io.h
+++ b/libgfortran/io/io.h
@@ -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);
diff --git a/libgfortran/io/list_read.c b/libgfortran/io/list_read.c
index 4d2ce794120..b0c4e5fca52 100644
--- a/libgfortran/io/list_read.c
+++ b/libgfortran/io/list_read.c
@@ -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
{
diff --git a/libgfortran/io/read.c b/libgfortran/io/read.c
index 32c8b3250f8..c493d5a5f43 100644
--- a/libgfortran/io/read.c
+++ b/libgfortran/io/read.c
@@ -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;
diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h
index 051e2e85a1e..7dafd940e62 100644
--- a/libgfortran/libgfortran.h
+++ b/libgfortran/libgfortran.h
@@ -535,7 +535,6 @@ typedef struct
size_t record_marker;
int max_subrecord_length;
int bounds_check;
- int range_check;
}
compile_options_t;
diff --git a/libgfortran/runtime/compile_options.c b/libgfortran/runtime/compile_options.c
index 0e657f73ba6..2ba1aedf5c5 100644
--- a/libgfortran/runtime/compile_options.c
+++ b/libgfortran/runtime/compile_options.c
@@ -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