From 3dedc65a1f69e0e9929f5d9c036e14bb25074d8a Mon Sep 17 00:00:00 2001 From: Doug Evans Date: Wed, 27 Aug 1997 16:58:02 +0000 Subject: [PATCH] c-decl.c (grokdeclarator): If array index or size calculations overflow, issue an error. * c-decl.c (grokdeclarator): If array index or size calculations overflow, issue an error. * fold-const.c (int_const_binop): New static function. (const_binop, size_binop): Call it. Brought over from the fsf. From-SVN: r14967 --- gcc/ChangeLog | 5 + gcc/c-decl.c | 19 +++ gcc/fold-const.c | 334 +++++++++++++++++++++++++---------------------- 3 files changed, 203 insertions(+), 155 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 473e0e2d410..4d422316d20 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,11 @@ Wed Aug 27 01:56:18 1997 Doug Evans * loop.c (combine_movables): Earlier insns don't match later ones. + * c-decl.c (grokdeclarator): If array index or size calculations + overflow, issue an error. + * fold-const.c (int_const_binop): New static function. + (const_binop, size_binop): Call it. + Wed Aug 27 01:24:25 1997 H.J. Lu (hjl@gnu.ai.mit.edu) * config/linux.h (CC1_SPEC): Define it only if not defined. diff --git a/gcc/c-decl.c b/gcc/c-decl.c index b556d0825f1..316ada71040 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -4672,6 +4672,18 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) convert (index_type, size), convert (index_type, size_one_node))); + /* If that overflowed, the array is too big. + ??? While a size of INT_MAX+1 technically shouldn't cause + an overflow (because we subtract 1), the overflow is recorded + during the conversion to index_type, before the subtraction. + Handling this case seems like an unnecessary complication. */ + if (TREE_OVERFLOW (itype)) + { + error ("size of array `%s' is too large", name); + type = error_mark_node; + continue; + } + if (size_varies) itype = variable_size (itype); itype = build_index_type (itype); @@ -4847,6 +4859,13 @@ grokdeclarator (declarator, declspecs, decl_context, initialized) /* Now TYPE has the actual type. */ + /* Did array size calculations overflow? */ + + if (TREE_CODE (type) == ARRAY_TYPE + && TYPE_SIZE (type) + && TREE_OVERFLOW (TYPE_SIZE (type))) + error ("size of array `%s' is too large", name); + /* If this is declaring a typedef name, return a TYPE_DECL. */ if (specbits & (1 << (int) RID_TYPEDEF)) diff --git a/gcc/fold-const.c b/gcc/fold-const.c index 10b13f33f7c..f62dd9460a0 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -62,6 +62,7 @@ int div_and_round_double PROTO((enum tree_code, int, HOST_WIDE_INT, HOST_WIDE_INT *)); static int split_tree PROTO((tree, enum tree_code, tree *, tree *, int *)); +static tree int_const_binop PROTO((enum tree_code, tree, tree, int, int)); static tree const_binop PROTO((enum tree_code, tree, tree, int)); static tree fold_convert PROTO((tree, tree)); static enum tree_code invert_tree_comparison PROTO((enum tree_code)); @@ -1051,192 +1052,215 @@ split_tree (in, code, varp, conp, varsignp) return 0; } -/* Combine two constants ARG1 and ARG2 under operation CODE +/* Combine two integer constants ARG1 and ARG2 under operation CODE to produce a new constant. - We assume ARG1 and ARG2 have the same data type, - or at least are the same kind of constant and the same machine mode. - If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ + If NOTRUNC is nonzero, do not truncate the result to fit the data type. + If FORSIZE is nonzero, compute overflow for unsigned types. */ static tree -const_binop (code, arg1, arg2, notrunc) +int_const_binop (code, arg1, arg2, notrunc, forsize) enum tree_code code; register tree arg1, arg2; - int notrunc; + int notrunc, forsize; { - STRIP_NOPS (arg1); STRIP_NOPS (arg2); + HOST_WIDE_INT int1l, int1h, int2l, int2h; + HOST_WIDE_INT low, hi; + HOST_WIDE_INT garbagel, garbageh; + register tree t; + int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); + int overflow = 0; + int no_overflow = 0; - if (TREE_CODE (arg1) == INTEGER_CST) + int1l = TREE_INT_CST_LOW (arg1); + int1h = TREE_INT_CST_HIGH (arg1); + int2l = TREE_INT_CST_LOW (arg2); + int2h = TREE_INT_CST_HIGH (arg2); + + switch (code) { - register HOST_WIDE_INT int1l = TREE_INT_CST_LOW (arg1); - register HOST_WIDE_INT int1h = TREE_INT_CST_HIGH (arg1); - HOST_WIDE_INT int2l = TREE_INT_CST_LOW (arg2); - HOST_WIDE_INT int2h = TREE_INT_CST_HIGH (arg2); - HOST_WIDE_INT low, hi; - HOST_WIDE_INT garbagel, garbageh; - register tree t; - int uns = TREE_UNSIGNED (TREE_TYPE (arg1)); - int overflow = 0; - int no_overflow = 0; + case BIT_IOR_EXPR: + low = int1l | int2l, hi = int1h | int2h; + break; - switch (code) - { - case BIT_IOR_EXPR: - low = int1l | int2l, hi = int1h | int2h; - break; + case BIT_XOR_EXPR: + low = int1l ^ int2l, hi = int1h ^ int2h; + break; - case BIT_XOR_EXPR: - low = int1l ^ int2l, hi = int1h ^ int2h; - break; + case BIT_AND_EXPR: + low = int1l & int2l, hi = int1h & int2h; + break; - case BIT_AND_EXPR: - low = int1l & int2l, hi = int1h & int2h; - break; + case BIT_ANDTC_EXPR: + low = int1l & ~int2l, hi = int1h & ~int2h; + break; - case BIT_ANDTC_EXPR: - low = int1l & ~int2l, hi = int1h & ~int2h; - break; + case RSHIFT_EXPR: + int2l = - int2l; + case LSHIFT_EXPR: + /* It's unclear from the C standard whether shifts can overflow. + The following code ignores overflow; perhaps a C standard + interpretation ruling is needed. */ + lshift_double (int1l, int1h, int2l, + TYPE_PRECISION (TREE_TYPE (arg1)), + &low, &hi, + !uns); + no_overflow = 1; + break; - case RSHIFT_EXPR: - int2l = - int2l; - case LSHIFT_EXPR: - /* It's unclear from the C standard whether shifts can overflow. - The following code ignores overflow; perhaps a C standard - interpretation ruling is needed. */ - lshift_double (int1l, int1h, int2l, - TYPE_PRECISION (TREE_TYPE (arg1)), - &low, &hi, - !uns); - no_overflow = 1; - break; + case RROTATE_EXPR: + int2l = - int2l; + case LROTATE_EXPR: + lrotate_double (int1l, int1h, int2l, + TYPE_PRECISION (TREE_TYPE (arg1)), + &low, &hi); + break; - case RROTATE_EXPR: - int2l = - int2l; - case LROTATE_EXPR: - lrotate_double (int1l, int1h, int2l, - TYPE_PRECISION (TREE_TYPE (arg1)), - &low, &hi); - break; + case PLUS_EXPR: + overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); + break; - case PLUS_EXPR: - overflow = add_double (int1l, int1h, int2l, int2h, &low, &hi); - break; + case MINUS_EXPR: + neg_double (int2l, int2h, &low, &hi); + add_double (int1l, int1h, low, hi, &low, &hi); + overflow = overflow_sum_sign (hi, int2h, int1h); + break; - case MINUS_EXPR: - neg_double (int2l, int2h, &low, &hi); - add_double (int1l, int1h, low, hi, &low, &hi); - overflow = overflow_sum_sign (hi, int2h, int1h); - break; + case MULT_EXPR: + overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi); + break; - case MULT_EXPR: - overflow = mul_double (int1l, int1h, int2l, int2h, &low, &hi); + case TRUNC_DIV_EXPR: + case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: + case EXACT_DIV_EXPR: + /* This is a shortcut for a common special case. */ + if (int2h == 0 && int2l > 0 + && ! TREE_CONSTANT_OVERFLOW (arg1) + && ! TREE_CONSTANT_OVERFLOW (arg2) + && int1h == 0 && int1l >= 0) + { + if (code == CEIL_DIV_EXPR) + int1l += int2l - 1; + low = int1l / int2l, hi = 0; break; + } - case TRUNC_DIV_EXPR: - case FLOOR_DIV_EXPR: case CEIL_DIV_EXPR: - case EXACT_DIV_EXPR: - /* This is a shortcut for a common special case. */ - if (int2h == 0 && int2l > 0 - && ! TREE_CONSTANT_OVERFLOW (arg1) - && ! TREE_CONSTANT_OVERFLOW (arg2) - && int1h == 0 && int1l >= 0) - { - if (code == CEIL_DIV_EXPR) - int1l += int2l - 1; - low = int1l / int2l, hi = 0; - break; - } - - /* ... fall through ... */ + /* ... fall through ... */ - case ROUND_DIV_EXPR: - if (int2h == 0 && int2l == 1) - { - low = int1l, hi = int1h; - break; - } - if (int1l == int2l && int1h == int2h - && ! (int1l == 0 && int1h == 0)) - { - low = 1, hi = 0; - break; - } - overflow = div_and_round_double (code, uns, - int1l, int1h, int2l, int2h, - &low, &hi, &garbagel, &garbageh); + case ROUND_DIV_EXPR: + if (int2h == 0 && int2l == 1) + { + low = int1l, hi = int1h; break; - - case TRUNC_MOD_EXPR: - case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: - /* This is a shortcut for a common special case. */ - if (int2h == 0 && int2l > 0 - && ! TREE_CONSTANT_OVERFLOW (arg1) - && ! TREE_CONSTANT_OVERFLOW (arg2) - && int1h == 0 && int1l >= 0) - { - if (code == CEIL_MOD_EXPR) - int1l += int2l - 1; - low = int1l % int2l, hi = 0; - break; - } - - /* ... fall through ... */ - - case ROUND_MOD_EXPR: - overflow = div_and_round_double (code, uns, - int1l, int1h, int2l, int2h, - &garbagel, &garbageh, &low, &hi); + } + if (int1l == int2l && int1h == int2h + && ! (int1l == 0 && int1h == 0)) + { + low = 1, hi = 0; break; + } + overflow = div_and_round_double (code, uns, + int1l, int1h, int2l, int2h, + &low, &hi, &garbagel, &garbageh); + break; - case MIN_EXPR: - case MAX_EXPR: - if (uns) - { - low = (((unsigned HOST_WIDE_INT) int1h - < (unsigned HOST_WIDE_INT) int2h) - || (((unsigned HOST_WIDE_INT) int1h - == (unsigned HOST_WIDE_INT) int2h) - && ((unsigned HOST_WIDE_INT) int1l - < (unsigned HOST_WIDE_INT) int2l))); - } - else - { - low = ((int1h < int2h) - || ((int1h == int2h) - && ((unsigned HOST_WIDE_INT) int1l - < (unsigned HOST_WIDE_INT) int2l))); - } - if (low == (code == MIN_EXPR)) - low = int1l, hi = int1h; - else - low = int2l, hi = int2h; + case TRUNC_MOD_EXPR: + case FLOOR_MOD_EXPR: case CEIL_MOD_EXPR: + /* This is a shortcut for a common special case. */ + if (int2h == 0 && int2l > 0 + && ! TREE_CONSTANT_OVERFLOW (arg1) + && ! TREE_CONSTANT_OVERFLOW (arg2) + && int1h == 0 && int1l >= 0) + { + if (code == CEIL_MOD_EXPR) + int1l += int2l - 1; + low = int1l % int2l, hi = 0; break; + } - default: - abort (); + /* ... fall through ... */ + + case ROUND_MOD_EXPR: + overflow = div_and_round_double (code, uns, + int1l, int1h, int2l, int2h, + &garbagel, &garbageh, &low, &hi); + break; + + case MIN_EXPR: + case MAX_EXPR: + if (uns) + { + low = (((unsigned HOST_WIDE_INT) int1h + < (unsigned HOST_WIDE_INT) int2h) + || (((unsigned HOST_WIDE_INT) int1h + == (unsigned HOST_WIDE_INT) int2h) + && ((unsigned HOST_WIDE_INT) int1l + < (unsigned HOST_WIDE_INT) int2l))); } - got_it: - if (TREE_TYPE (arg1) == sizetype && hi == 0 - && low >= 0 && low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype)) - && ! overflow - && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2)) - t = size_int (low); else { - t = build_int_2 (low, hi); - TREE_TYPE (t) = TREE_TYPE (arg1); + low = ((int1h < int2h) + || ((int1h == int2h) + && ((unsigned HOST_WIDE_INT) int1l + < (unsigned HOST_WIDE_INT) int2l))); } + if (low == (code == MIN_EXPR)) + low = int1l, hi = int1h; + else + low = int2l, hi = int2h; + break; - TREE_OVERFLOW (t) - = ((notrunc ? !uns && overflow - : force_fit_type (t, overflow && !uns) && ! no_overflow) - | TREE_OVERFLOW (arg1) - | TREE_OVERFLOW (arg2)); - TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t) - | TREE_CONSTANT_OVERFLOW (arg1) - | TREE_CONSTANT_OVERFLOW (arg2)); - return t; + default: + abort (); } + + if (TREE_TYPE (arg1) == sizetype && hi == 0 + && low >= 0 && low <= TREE_INT_CST_LOW (TYPE_MAX_VALUE (sizetype)) + && ! overflow + && ! TREE_OVERFLOW (arg1) && ! TREE_OVERFLOW (arg2)) + t = size_int (low); + else + { + t = build_int_2 (low, hi); + TREE_TYPE (t) = TREE_TYPE (arg1); + } + + TREE_OVERFLOW (t) + = ((notrunc ? (!uns || forsize) && overflow + : force_fit_type (t, (!uns || forsize) && overflow) && ! no_overflow) + | TREE_OVERFLOW (arg1) + | TREE_OVERFLOW (arg2)); + /* If we're doing a size calculation, unsigned arithmetic does overflow. + So check if force_fit_type truncated the value. */ + if (forsize + && ! TREE_OVERFLOW (t) + && (TREE_INT_CST_HIGH (t) != hi + || TREE_INT_CST_LOW (t) != low)) + TREE_OVERFLOW (t) = 1; + TREE_CONSTANT_OVERFLOW (t) = (TREE_OVERFLOW (t) + | TREE_CONSTANT_OVERFLOW (arg1) + | TREE_CONSTANT_OVERFLOW (arg2)); + return t; +} + +/* Combine two constants ARG1 and ARG2 under operation CODE + to produce a new constant. + We assume ARG1 and ARG2 have the same data type, + or at least are the same kind of constant and the same machine mode. + + If NOTRUNC is nonzero, do not truncate the result to fit the data type. */ + +static tree +const_binop (code, arg1, arg2, notrunc) + enum tree_code code; + register tree arg1, arg2; + int notrunc; +{ + STRIP_NOPS (arg1); STRIP_NOPS (arg2); + + if (TREE_CODE (arg1) == INTEGER_CST) + return int_const_binop (code, arg1, arg2, notrunc, 0); + #if ! defined (REAL_IS_NOT_DOUBLE) || defined (REAL_ARITHMETIC) if (TREE_CODE (arg1) == REAL_CST) { @@ -1450,7 +1474,7 @@ size_binop (code, arg0, arg1) return arg1; /* Handle general case of two integer constants. */ - return const_binop (code, arg0, arg1, 0); + return int_const_binop (code, arg0, arg1, 0, 1); } if (arg0 == error_mark_node || arg1 == error_mark_node) -- 2.30.2