From 268209f3a0dc07fcf13534610447ab732742eb2f Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Thu, 5 Dec 2019 01:28:11 +0000 Subject: [PATCH] PR middle-end/91582 - missing heap overflow detection for strcpy gcc/ChangeLog: PR middle-end/91582 * builtins.c (gimple_call_alloc_size): New function. (compute_objsize): Add argument. Call gimple_call_alloc_size. Handle variable offsets and indices. * builtins.h (gimple_call_alloc_size): Declare. (compute_objsize): Add argument. * gcc/gimple-ssa-warn-restrict.c: Remove assertions. * tree-ssa-strlen.c (handle_store): Handle calls to allocated objects. gcc/testsuite/ChangeLog: PR middle-end/91582 * c-c++-common/Wstringop-truncation.c: Remove xfails. * g++.dg/warn/Wstringop-overflow-4.C: New test. * g++.dg/ext/attr-alloc_size.C: Suppress -Warray-bounds. * gcc.dg/Warray-bounds-56.c: New test. * gcc.dg/Wstringop-overflow-22.c: New test. * gcc.dg/attr-alloc_size.c: Suppress -Warray-bounds. * gcc.dg/attr-copy-2.c: Same. * gcc.dg/builtin-stringop-chk-5.c: Remove xfails. * gcc.dg/builtin-stringop-chk-8.c: Same. Correct the text of expected warnings. * gcc.target/i386/pr82002-2a.c: Prune expected warning. * gcc.target/i386/pr82002-2b.c: Same. From-SVN: r278983 --- gcc/ChangeLog | 11 + gcc/builtins.c | 230 ++++++++++- gcc/builtins.h | 3 +- gcc/gimple-ssa-warn-restrict.c | 2 - gcc/testsuite/ChangeLog | 15 + .../c-c++-common/Wstringop-truncation.c | 2 +- gcc/testsuite/g++.dg/ext/attr-alloc_size.C | 2 +- .../g++.dg/warn/Wstringop-overflow-4.C | 157 ++++++++ gcc/testsuite/gcc.dg/Warray-bounds-56.c | 88 ++++ gcc/testsuite/gcc.dg/Wstringop-overflow-25.c | 377 ++++++++++++++++++ gcc/testsuite/gcc.dg/attr-alloc_size.c | 2 +- gcc/testsuite/gcc.dg/attr-copy-2.c | 2 +- gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c | 12 +- gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c | 10 +- gcc/testsuite/gcc.target/i386/pr82002-2a.c | 2 + gcc/testsuite/gcc.target/i386/pr82002-2b.c | 2 + gcc/tree-ssa-strlen.c | 18 +- 17 files changed, 895 insertions(+), 40 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C create mode 100644 gcc/testsuite/gcc.dg/Warray-bounds-56.c create mode 100644 gcc/testsuite/gcc.dg/Wstringop-overflow-25.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 096c75ea80b..7f44667ab21 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,14 @@ +2019-12-03 Martin Sebor + + PR middle-end/91582 + * builtins.c (gimple_call_alloc_size): New function. + (compute_objsize): Add argument. Call gimple_call_alloc_size. + Handle variable offsets and indices. + * builtins.h (gimple_call_alloc_size): Declare. + (compute_objsize): Add argument. + * gcc/gimple-ssa-warn-restrict.c: Remove assertions. + * tree-ssa-strlen.c (handle_store): Handle calls to allocated objects. + 2019-12-04 Julian Brown * config/gcn/gcn.h (FIXED_REGISTERS): Make s6/s7 fixed registers. diff --git a/gcc/builtins.c b/gcc/builtins.c index 36319a97b52..53de17c105f 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -3696,6 +3696,97 @@ check_access (tree exp, tree, tree, tree dstwrite, return true; } +/* If STMT is a call to an allocation function, returns the size + of the object allocated by the call. */ + +tree +gimple_call_alloc_size (gimple *stmt) +{ + if (!stmt) + return NULL_TREE; + + tree allocfntype; + if (tree fndecl = gimple_call_fndecl (stmt)) + allocfntype = TREE_TYPE (fndecl); + else + allocfntype = gimple_call_fntype (stmt); + + if (!allocfntype) + return NULL_TREE; + + unsigned argidx1 = UINT_MAX, argidx2 = UINT_MAX; + tree at = lookup_attribute ("alloc_size", TYPE_ATTRIBUTES (allocfntype)); + if (!at) + { + if (!gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN)) + return NULL_TREE; + + argidx1 = 0; + } + + unsigned nargs = gimple_call_num_args (stmt); + + if (argidx1 == UINT_MAX) + { + tree atval = TREE_VALUE (at); + if (!atval) + return NULL_TREE; + + argidx1 = TREE_INT_CST_LOW (TREE_VALUE (atval)) - 1; + if (nargs <= argidx1) + return NULL_TREE; + + atval = TREE_CHAIN (atval); + if (atval) + { + argidx2 = TREE_INT_CST_LOW (TREE_VALUE (atval)) - 1; + if (nargs <= argidx2) + return NULL_TREE; + } + } + + tree size = gimple_call_arg (stmt, argidx1); + + wide_int rng1[2]; + if (TREE_CODE (size) == INTEGER_CST) + rng1[0] = rng1[1] = wi::to_wide (size); + else if (TREE_CODE (size) != SSA_NAME + || get_range_info (size, rng1, rng1 + 1) != VR_RANGE) + return NULL_TREE; + + if (argidx2 > nargs && TREE_CODE (size) == INTEGER_CST) + return size; + + /* To handle ranges do the math in wide_int and return the product + of the upper bounds as a constant. Ignore anti-ranges. */ + tree n = argidx2 < nargs ? gimple_call_arg (stmt, argidx2) : integer_one_node; + wide_int rng2[2]; + if (TREE_CODE (n) == INTEGER_CST) + rng2[0] = rng2[1] = wi::to_wide (n); + else if (TREE_CODE (n) != SSA_NAME + || get_range_info (n, rng2, rng2 + 1) != VR_RANGE) + return NULL_TREE; + + /* Extend to the maximum precsion to avoid overflow. */ + const int prec = ADDR_MAX_PRECISION; + rng1[0] = wide_int::from (rng1[0], prec, UNSIGNED); + rng1[1] = wide_int::from (rng1[1], prec, UNSIGNED); + rng2[0] = wide_int::from (rng2[0], prec, UNSIGNED); + rng2[1] = wide_int::from (rng2[1], prec, UNSIGNED); + + /* Return the lesser of SIZE_MAX and the product of the upper bounds. */ + rng1[0] = rng1[0] * rng2[0]; + rng1[1] = rng1[1] * rng2[1]; + tree size_max = TYPE_MAX_VALUE (sizetype); + if (wi::gtu_p (rng1[1], wi::to_wide (size_max, prec))) + { + rng1[1] = wi::to_wide (size_max); + return size_max; + } + + return wide_int_to_tree (sizetype, rng1[1]); +} + /* Helper to compute the size of the object referenced by the DEST expression which must have pointer type, using Object Size type OSTYPE (only the least significant 2 bits are used). Return @@ -3704,16 +3795,22 @@ check_access (tree exp, tree, tree, tree dstwrite, a non-constant offset in some range the returned value represents the largest size given the smallest non-negative offset in the range. If nonnull, set *PDECL to the decl of the referenced - subobject if it can be determined, or to null otherwise. + subobject if it can be determined, or to null otherwise. Likewise, + when POFF is nonnull *POFF is set to the offset into *PDECL. The function is intended for diagnostics and should not be used to influence code generation or optimization. */ tree -compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) +compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */, + tree *poff /* = NULL */) { - tree dummy = NULL_TREE; + tree dummy_decl = NULL_TREE; if (!pdecl) - pdecl = &dummy; + pdecl = &dummy_decl; + + tree dummy_off = size_zero_node; + if (!poff) + poff = &dummy_off; unsigned HOST_WIDE_INT size; @@ -3726,6 +3823,13 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) if (TREE_CODE (dest) == SSA_NAME) { gimple *stmt = SSA_NAME_DEF_STMT (dest); + if (is_gimple_call (stmt)) + { + /* If STMT is a call to an allocation function get the size + from its argument(s). */ + return gimple_call_alloc_size (stmt); + } + if (!is_gimple_assign (stmt)) return NULL_TREE; @@ -3741,7 +3845,7 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) tree off = gimple_assign_rhs2 (stmt); if (TREE_CODE (off) == INTEGER_CST) { - if (tree size = compute_objsize (dest, ostype, pdecl)) + if (tree size = compute_objsize (dest, ostype, pdecl, poff)) { wide_int wioff = wi::to_wide (off); wide_int wisiz = wi::to_wide (size); @@ -3752,10 +3856,16 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) if (wi::sign_mask (wioff)) ; else if (wi::ltu_p (wioff, wisiz)) - return wide_int_to_tree (TREE_TYPE (size), - wi::sub (wisiz, wioff)); + { + *poff = size_binop (PLUS_EXPR, *poff, off); + return wide_int_to_tree (TREE_TYPE (size), + wi::sub (wisiz, wioff)); + } else - return size_zero_node; + { + *poff = size_binop (PLUS_EXPR, *poff, off); + return size_zero_node; + } } } else if (TREE_CODE (off) == SSA_NAME @@ -3777,10 +3887,18 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) || wi::sign_mask (max)) ; else if (wi::ltu_p (min, wisiz)) - return wide_int_to_tree (TREE_TYPE (size), - wi::sub (wisiz, min)); + { + *poff = size_binop (PLUS_EXPR, *poff, + wide_int_to_tree (sizetype, min)); + return wide_int_to_tree (TREE_TYPE (size), + wi::sub (wisiz, min)); + } else - return size_zero_node; + { + *poff = size_binop (PLUS_EXPR, *poff, + wide_int_to_tree (sizetype, min)); + return size_zero_node; + } } } } @@ -3799,19 +3917,24 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) { tree ref = TREE_OPERAND (dest, 0); tree off = TREE_OPERAND (dest, 1); - if (tree size = compute_objsize (ref, ostype, pdecl)) + if (tree size = compute_objsize (ref, ostype, pdecl, poff)) { /* If the declaration of the destination object is known to have zero size, return zero. */ - if (integer_zerop (size)) + if (integer_zerop (size) + && *pdecl && DECL_P (*pdecl) + && *poff && integer_zerop (*poff)) return integer_zero_node; - if (TREE_CODE (off) != INTEGER_CST - || TREE_CODE (size) != INTEGER_CST) - return NULL_TREE; + /* A valid offset into a declared object cannot be negative. */ + if (tree_int_cst_sgn (*poff) < 0) + return size_zero_node; + /* Adjust SIZE either up or down by the sum of *POFF and OFF + above. */ if (TREE_CODE (dest) == ARRAY_REF) { + /* Convert the array index into a byte offset. */ tree eltype = TREE_TYPE (dest); tree tpsize = TYPE_SIZE_UNIT (eltype); if (tpsize && TREE_CODE (tpsize) == INTEGER_CST) @@ -3820,9 +3943,74 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) return NULL_TREE; } - if (tree_int_cst_lt (off, size)) - return fold_build2 (MINUS_EXPR, size_type_node, size, off); - return integer_zero_node; + wide_int offrng[2]; + if (TREE_CODE (off) == INTEGER_CST) + offrng[0] = offrng[1] = wi::to_wide (off); + else if (TREE_CODE (off) == SSA_NAME) + { + wide_int min, max; + enum value_range_kind rng + = get_range_info (off, offrng, offrng + 1); + if (rng != VR_RANGE) + return NULL_TREE; + } + else + return NULL_TREE; + + /* Convert to the same precision to keep wide_int from "helpfuly" + crashing whenever it sees other argumments. */ + offrng[0] = wide_int::from (offrng[0], ADDR_MAX_BITSIZE, SIGNED); + offrng[1] = wide_int::from (offrng[1], ADDR_MAX_BITSIZE, SIGNED); + + tree dstoff = *poff; + if (integer_zerop (*poff)) + *poff = off; + else if (!integer_zerop (off)) + { + *poff = fold_convert (ptrdiff_type_node, *poff); + off = fold_convert (ptrdiff_type_node, off); + *poff = size_binop (PLUS_EXPR, *poff, off); + } + + if (wi::sign_mask (offrng[0]) >= 0) + { + if (TREE_CODE (size) != INTEGER_CST) + return NULL_TREE; + + /* Return the difference between the size and the offset + or zero if the offset is greater. */ + wide_int wisize = wi::to_wide (size, ADDR_MAX_BITSIZE); + if (wi::ltu_p (wisize, offrng[0])) + return size_zero_node; + + return wide_int_to_tree (sizetype, wisize - offrng[0]); + } + + wide_int dstoffrng[2]; + if (TREE_CODE (dstoff) == INTEGER_CST) + dstoffrng[0] = dstoffrng[1] = wi::to_wide (dstoff); + else if (TREE_CODE (dstoff) == SSA_NAME) + { + enum value_range_kind rng + = get_range_info (dstoff, dstoffrng, dstoffrng + 1); + if (rng != VR_RANGE) + return NULL_TREE; + } + else + return NULL_TREE; + + dstoffrng[0] = wide_int::from (dstoffrng[0], ADDR_MAX_BITSIZE, SIGNED); + dstoffrng[1] = wide_int::from (dstoffrng[1], ADDR_MAX_BITSIZE, SIGNED); + + wide_int declsize = wi::to_wide (size); + if (wi::sign_mask (dstoffrng[0]) > 0) + declsize += dstoffrng[0]; + + offrng[1] += dstoffrng[1]; + if (wi::sign_mask (offrng[1]) < 0) + return size_zero_node; + + return wide_int_to_tree (sizetype, declsize); } return NULL_TREE; @@ -3850,9 +4038,11 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */) type = TREE_TYPE (type); type = TYPE_MAIN_VARIANT (type); + if (TREE_CODE (dest) == ADDR_EXPR) + dest = TREE_OPERAND (dest, 0); if (TREE_CODE (type) == ARRAY_TYPE - && !array_at_struct_end_p (ref)) + && !array_at_struct_end_p (dest)) { if (tree size = TYPE_SIZE_UNIT (type)) return TREE_CODE (size) == INTEGER_CST ? size : NULL_TREE; diff --git a/gcc/builtins.h b/gcc/builtins.h index aa83a46a684..0fcccc12a39 100644 --- a/gcc/builtins.h +++ b/gcc/builtins.h @@ -133,7 +133,8 @@ extern tree fold_call_stmt (gcall *, bool); extern void set_builtin_user_assembler_name (tree decl, const char *asmspec); extern bool is_simple_builtin (tree); extern bool is_inexpensive_builtin (tree); -extern tree compute_objsize (tree, int, tree * = NULL); +extern tree gimple_call_alloc_size (gimple *); +extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL); extern bool readonly_data_expr (tree exp); extern bool init_target_chars (void); diff --git a/gcc/gimple-ssa-warn-restrict.c b/gcc/gimple-ssa-warn-restrict.c index 2cf84b7aac2..9b5d1d79599 100644 --- a/gcc/gimple-ssa-warn-restrict.c +++ b/gcc/gimple-ssa-warn-restrict.c @@ -966,7 +966,6 @@ builtin_access::generic_overlap () const offset_int maxobjsize = acs.dstref->maxobjsize; offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; - gcc_assert (maxsize <= maxobjsize); /* Adjust the larger bounds of the offsets (which may be the first element if the lower bound is larger than the upper bound) to @@ -1193,7 +1192,6 @@ builtin_access::strcat_overlap () acs.dstsiz[1] = 1; offset_int maxsize = dstref->basesize < 0 ? maxobjsize : dstref->basesize; - gcc_assert (maxsize <= maxobjsize); /* For references to the same base object, determine if there's a pair of valid offsets into the two references such that access between diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 48a6d4501ad..477a3b23a8f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,18 @@ +2019-12-03 Martin Sebor + + PR middle-end/91582 + * c-c++-common/Wstringop-truncation.c: Remove xfails. + * g++.dg/warn/Wstringop-overflow-4.C: New test. + * gcc/testsuite/g++.dg/ext/attr-alloc_size.C: Suppress -Warray-bounds. + * gcc.dg/Wstringop-overflow-25.c: New test. + * gcc/testsuite/gcc.dg/attr-alloc_size.c: Suppress -Warray-bounds. + * gcc/testsuite/gcc.dg/attr-copy-2.c: Same. + * gcc.dg/builtin-stringop-chk-5.c: Remove xfails. + * gcc.dg/builtin-stringop-chk-8.c: Same. Correct the text of expected + warnings. + * gcc.target/i386/pr82002-2a.c: Prune expected warning. + * gcc.target/i386/pr82002-2b.c: Same. + 2019-12-04 Joseph Myers PR c/36941 diff --git a/gcc/testsuite/c-c++-common/Wstringop-truncation.c b/gcc/testsuite/c-c++-common/Wstringop-truncation.c index b85711d6b3f..592a9494ca4 100644 --- a/gcc/testsuite/c-c++-common/Wstringop-truncation.c +++ b/gcc/testsuite/c-c++-common/Wstringop-truncation.c @@ -425,7 +425,7 @@ void test_strncpy_alloc (const char* s) size_t n = 7; char *d = (char *)__builtin_malloc (n); - CPY (d, s, n); /* { dg-warning "specified bound 7 equals destination size" "bug 79016" { xfail *-*-* } } */ + CPY (d, s, n); /* { dg-warning "specified bound 7 equals destination size" } */ Dest *pd = (Dest *)__builtin_malloc (sizeof *pd * n); CPY (pd->a5, s, 5); /* { dg-warning "specified bound 5 equals destination size" } */ diff --git a/gcc/testsuite/g++.dg/ext/attr-alloc_size.C b/gcc/testsuite/g++.dg/ext/attr-alloc_size.C index 9a421109bdb..9194417aee6 100644 --- a/gcc/testsuite/g++.dg/ext/attr-alloc_size.C +++ b/gcc/testsuite/g++.dg/ext/attr-alloc_size.C @@ -1,6 +1,6 @@ /* PR c++/87541 - ICE using a constant decl as an attribute alloc_size argument { dg-do compile } - { dg-options "-O2 -Wall" } */ + { dg-options "-O2 -Wall -Wno-array-bounds" } */ #define ALLOC_SIZE(N) __attribute__ ((alloc_size (N))) diff --git a/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C new file mode 100644 index 00000000000..b6fe0289674 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C @@ -0,0 +1,157 @@ +/* PR middle-end/91582 - missing heap overflow detection for strcpy + { dg-do compile } + { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */ + +#include "../../gcc.dg/range.h" + +#define INT_MAX __INT_MAX__ +#define INT_MIN (-INT_MAX - 1) + +extern "C" char* strcpy (char*, const char*); + +void sink (void*); + +#define S36 "0123456789abcdefghijklmnopqrstuvwxyz" +#define S(N) (S36 + sizeof S36 - N - 1) + +#define T(src, alloc) do { \ + const char *s = src; \ + char *d = (char*)alloc; \ + strcpy (d, s); \ + sink (d); \ + } while (0) + + +void test_strcpy_new_char (size_t n) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (S (0), new char[r_0_1]); + T (S (1), new char[r_0_1]); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), new char[r_1_2]); + T (S (1), new char[r_1_2]); + T (S (2), new char[r_1_2]); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), new char[r_2_3]); + T (S (2), new char[r_2_3]); + T (S (3), new char[r_2_3]); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), new char[r_2_3]); // { dg-warning "\\\[-Wstringop-overflow" } + + size_t r_2_smax = UR (2, SIZE_MAX); + T (S (0), new char[r_2_smax]); + T (S (1), new char[r_2_smax]); + T (S (2), new char[r_2_smax]); + T (S (3), new char[r_2_smax * 2]); + T (S (4), new char[r_2_smax * 2 + 1]); + + T (S (1), new char[n]); + T (S (2), new char[n + 1]); + T (S (9), new char[n * 2 + 1]); + + int r_imin_imax = SR (INT_MIN, INT_MAX); + T (S (1), new char[r_imin_imax]); + T (S (2), new char[r_imin_imax + 1]); + T (S (9), new char[r_imin_imax * 2 + 1]); + + int r_0_imax = SR (0, INT_MAX); + T (S (1), new char[r_0_imax]); + T (S (2), new char[r_0_imax + 1]); + T (S (9), new char[r_0_imax * 2 + 1]); + + int r_1_imax = SR (1, INT_MAX); + T (S (1), new char[r_1_imax]); + T (S (2), new char[r_1_imax + 1]); + T (S (9), new char[r_1_imax * 2 + 1]); + + ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX); + T (S (1), new char[r_dmin_dmax]); + T (S (2), new char[r_dmin_dmax + 1]); + T (S (9), new char[r_dmin_dmax * 2 + 1]); +} + + +void test_strcpy_new_char_array (size_t n) +{ + size_t r_0_1 = UR (0, 1); + + T (S (0), new char[r_0_1][1]); + T (S (1), new char[r_0_1][1]); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (1), new char[r_0_1][2]); + T (S (2), new char[r_0_1][2]); // { dg-warning "\\\[-Wstringop-overflow" } + + size_t r_1_2 = UR (1, 2); + T (S (0), new char[r_1_2][0]); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (0), new char[r_1_2][1]); + T (S (1), new char[r_1_2][1]); + T (S (2), new char[r_1_2][1]); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), new char[r_1_2][0]); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (0), new char[r_1_2][1]); + T (S (1), new char[r_1_2][2]); + T (S (3), new char[r_1_2][2]); + T (S (4), new char[r_1_2][2]); // { dg-warning "\\\[-Wstringop-overflow" } +} + + +#ifdef __INT16_TYPE__ + +typedef __INT16_TYPE__ int16_t; + +void test_strcpy_new_int16_t (size_t n) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (S (0), new int16_t[r_0_1]); + T (S (1), new int16_t[r_0_1]); + T (S (2), new int16_t[r_0_1]); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), new int16_t[r_1_2]); + T (S (1), new int16_t[r_1_2]); + T (S (2), new int16_t[r_1_2]); + T (S (3), new int16_t[r_1_2]); + T (S (4), new int16_t[r_1_2]); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), new int16_t[r_2_3]); + T (S (1), new int16_t[r_2_3]); + T (S (5), new int16_t[r_2_3]); + T (S (6), new int16_t[r_2_3]); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), new int16_t[r_2_3]); // { dg-warning "\\\[-Wstringop-overflow" } + + size_t r_2_smax = UR (2, SIZE_MAX); + T (S (0), new int16_t[r_2_smax]); + T (S (1), new int16_t[r_2_smax]); + T (S (2), new int16_t[r_2_smax]); + T (S (3), new int16_t[r_2_smax * 2]); + T (S (4), new int16_t[r_2_smax * 2 + 1]); + + T (S (1), new int16_t[n]); + T (S (2), new int16_t[n + 1]); + T (S (9), new int16_t[n * 2 + 1]); + + int r_imin_imax = SR (INT_MIN, INT_MAX); + T (S (1), new int16_t[r_imin_imax]); + T (S (2), new int16_t[r_imin_imax + 1]); + T (S (9), new int16_t[r_imin_imax * 2 + 1]); + + int r_0_imax = SR (0, INT_MAX); + T (S (1), new int16_t[r_0_imax]); + T (S (2), new int16_t[r_0_imax + 1]); + T (S (9), new int16_t[r_0_imax * 2 + 1]); + + int r_1_imax = SR (1, INT_MAX); + T (S (1), new int16_t[r_1_imax]); + T (S (2), new int16_t[r_1_imax + 1]); + T (S (9), new int16_t[r_1_imax * 2 + 1]); + + ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX); + T (S (1), new int16_t[r_dmin_dmax]); + T (S (2), new int16_t[r_dmin_dmax + 1]); + T (S (9), new int16_t[r_dmin_dmax * 2 + 1]); +} + +#endif // int16_t diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-56.c b/gcc/testsuite/gcc.dg/Warray-bounds-56.c new file mode 100644 index 00000000000..3d85660fbbe --- /dev/null +++ b/gcc/testsuite/gcc.dg/Warray-bounds-56.c @@ -0,0 +1,88 @@ +/* PR middle-end/91582 - missing heap overflow detection for strcpy + + The -Warray-bounds instances here probably should be replaced by + -Wstringop-overflow when it detects these overflows (see also + the xfails in Wstringop-overflow-25.c). + + { dg-do compile } + { dg-options "-O2 -Wall -Wno-stringop-overflow -ftrack-macro-expansion=0" } */ + +#include "range.h" + +#define INT_MAX __INT_MAX__ +#define INT_MIN (-INT_MAX - 1) + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define NOIPA ATTR (noipa) + +extern void* malloc (size_t); +extern char* strcpy (char*, const char*); + +void sink (void*); + +#define S36 "0123456789abcdefghijklmnopqrstuvwxyz" +#define S(N) (S36 + sizeof S36 - N - 1) + +struct Flex +{ + char n, ax[]; +}; + +extern struct Flex fx; +struct Flex f1 = { 1, { 1 } }; +struct Flex f2 = { 2, { 1, 2 } }; +struct Flex f3 = { 3, { 1, 2, 3 } }; + +#define T(src, f) do { \ + char *s = src; \ + char *d = f.ax; \ + strcpy (d, s); \ + sink (&f); \ + } while (0) + +NOIPA void test_strcpy_flexarray (void) +{ + T (S (0), fx); // { dg-bogus "\\\[-Warray-bounds" "pr92815" { xfail *-*-*} } + T (S (9), fx); // { dg-bogus "\\\[-Warray-bounds" "pr92815" { xfail *-*-*} } + + T (S (0), f1); + T (S (1), f1); // { dg-warning "\\\[-Warray-bounds" } + + T (S (0), f2); + T (S (1), f2); + T (S (2), f2); // { dg-warning "\\\[-Warray-bounds" } + + T (S (0), f3); + T (S (2), f3); + T (S (3), f3); // { dg-warning "\\\[-Warray-bounds" } + T (S (9), f3); // { dg-warning "\\\[-Warray-bounds" } +} + +#undef T +#define T(T, src, n) do { \ + char *s = src; \ + typedef struct { T n, ax[]; } Flex; \ + Flex *p = (Flex*)malloc (sizeof *p + n); \ + char *d = (char*)p->ax; \ + strcpy (d, s); \ + sink (p); \ + } while (0) + +NOIPA void test_strcpy_malloc_flexarray (void) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (char, S (0), r_0_1); + T (char, S (1), r_0_1); // { dg-warning "\\\[-Warray-bounds" } + + T (char, S (0), r_1_2); + T (char, S (1), r_1_2); + T (char, S (2), r_1_2); // { dg-warning "\\\[-Warray-bounds" } + + T (char, S (0), r_2_3); + T (char, S (2), r_2_3); + T (char, S (3), r_2_3); // { dg-warning "\\\[-Warray-bounds" } + T (char, S (9), r_2_3); // { dg-warning "\\\[-Warray-bounds" } +} diff --git a/gcc/testsuite/gcc.dg/Wstringop-overflow-25.c b/gcc/testsuite/gcc.dg/Wstringop-overflow-25.c new file mode 100644 index 00000000000..1b38dfe9ae4 --- /dev/null +++ b/gcc/testsuite/gcc.dg/Wstringop-overflow-25.c @@ -0,0 +1,377 @@ +/* PR middle-end/91582 - missing heap overflow detection for strcpy + { dg-do compile } + { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */ + +#include "range.h" + +#define INT_MAX __INT_MAX__ +#define INT_MIN (-INT_MAX - 1) + +#define ATTR(...) __attribute__ ((__VA_ARGS__)) +#define NOIPA ATTR (noipa) + +extern void* alloca (size_t); +extern void* calloc (size_t, size_t); +extern void* malloc (size_t); + +extern ATTR (alloc_size (1), malloc) void* + alloc1 (size_t, int); +extern ATTR (alloc_size (2), malloc) void* + alloc2 (int, size_t); +extern ATTR (alloc_size (2, 4), malloc) void* + alloc2_4 (int, size_t, int, size_t); + +extern char* strcpy (char*, const char*); + +void sink (void*); + +#define S36 "0123456789abcdefghijklmnopqrstuvwxyz" +#define S(N) (S36 + sizeof S36 - N - 1) + +#define T(src, alloc) do { \ + char *s = src; \ + char *d = alloc; \ + strcpy (d, s); \ + sink (d); \ + } while (0) + + +NOIPA void test_strcpy_alloca (size_t n) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (S (0), alloca (r_0_1)); + T (S (1), alloca (r_0_1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloca (r_1_2)); + T (S (1), alloca (r_1_2)); + T (S (2), alloca (r_1_2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloca (r_2_3)); + T (S (2), alloca (r_2_3)); + T (S (3), alloca (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), alloca (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + + size_t r_2_smax = UR (2, SIZE_MAX); + T (S (0), alloca (r_2_smax)); + T (S (1), alloca (r_2_smax)); + T (S (2), alloca (r_2_smax)); + T (S (3), alloca (r_2_smax * 2)); + T (S (4), alloca (r_2_smax * 2 + 1)); + + T (S (1), alloca (n)); + T (S (2), alloca (n + 1)); + T (S (9), alloca (n * 2 + 1)); + + int r_imin_imax = SR (INT_MIN, INT_MAX); + T (S (1), alloca (r_imin_imax)); + T (S (2), alloca (r_imin_imax + 1)); + T (S (9), alloca (r_imin_imax * 2 + 1)); + + int r_0_imax = SR (0, INT_MAX); + T (S (1), alloca (r_0_imax)); + T (S (2), alloca (r_0_imax + 1)); + T (S (9), alloca (r_0_imax * 2 + 1)); + + int r_1_imax = SR (1, INT_MAX); + T (S (1), alloca (r_1_imax)); + T (S (2), alloca (r_1_imax + 1)); + T (S (9), alloca (r_1_imax * 2 + 1)); + + ptrdiff_t r_dmin_dmax = SR (DIFF_MIN, DIFF_MAX); + T (S (1), alloca (r_dmin_dmax)); + T (S (2), alloca (r_dmin_dmax + 1)); + T (S (9), alloca (r_dmin_dmax * 2 + 1)); +} + +NOIPA void test_strcpy_calloc (void) +{ + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (S (0), calloc (r_1_2, 1)); + T (S (1), calloc (r_1_2, 1)); + T (S (2), calloc (r_1_2, 1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (2), calloc (r_2_3, 1)); + T (S (3), calloc (r_2_3, 1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), calloc (1, r_1_2)); + T (S (1), calloc (1, r_1_2)); + T (S (2), calloc (1, r_1_2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (2), calloc (1, r_2_3)); + T (S (3), calloc (1, r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), calloc (r_1_2, 2)); + T (S (1), calloc (r_1_2, 2)); + T (S (2), calloc (r_1_2, 2)); + T (S (3), calloc (r_1_2, 2)); + T (S (4), calloc (r_1_2, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), calloc (r_2_3, 2)); + T (S (1), calloc (r_2_3, 2)); + T (S (2), calloc (r_2_3, 2)); + T (S (5), calloc (r_2_3, 2)); + T (S (6), calloc (r_2_3, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), calloc (r_1_2, 2)); + T (S (1), calloc (r_1_2, 2)); + T (S (2), calloc (r_1_2, 2)); + T (S (3), calloc (r_1_2, 2)); + T (S (4), calloc (r_1_2, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), calloc (r_2_3, 2)); + T (S (1), calloc (r_2_3, 2)); + T (S (2), calloc (r_2_3, 2)); + T (S (5), calloc (r_2_3, 2)); + T (S (6), calloc (r_2_3, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), calloc (r_1_2, r_2_3)); + T (S (1), calloc (r_1_2, r_2_3)); + T (S (2), calloc (r_1_2, r_2_3)); + T (S (3), calloc (r_1_2, r_2_3)); + T (S (4), calloc (r_1_2, r_2_3)); + T (S (5), calloc (r_1_2, r_2_3)); + T (S (6), calloc (r_1_2, r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), calloc (r_1_2, r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + + size_t r_2_dmax = UR (2, DIFF_MAX); + T (S (0), calloc (0, r_2_dmax)); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (0), calloc (1, r_2_dmax)); + T (S (9), calloc (2, r_2_dmax)); + + T (S (0), calloc (r_2_dmax, r_2_dmax)); + T (S (9), calloc (r_2_dmax, r_2_dmax)); + + size_t r_2_smax = UR (2, SIZE_MAX); + T (S (0), calloc (r_2_smax, 1)); + T (S (9), calloc (r_2_smax, 2)); + + T (S (0), calloc (r_2_smax, r_2_smax)); + T (S (9), calloc (r_2_smax, r_2_smax)); +} + + +NOIPA void test_strcpy_malloc (void) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (S (0), malloc (r_0_1)); + T (S (1), malloc (r_0_1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), malloc (r_1_2)); + T (S (1), malloc (r_1_2)); + T (S (2), malloc (r_1_2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), malloc (r_2_3)); + T (S (2), malloc (r_2_3)); + T (S (3), malloc (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), malloc (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } +} + + +NOIPA void test_strcpy_alloc1 (void) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + +#define alloc1(n) alloc1 (n, 1) + + T (S (0), alloc1 (r_0_1)); + T (S (1), alloc1 (r_0_1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc1 (r_1_2)); + T (S (1), alloc1 (r_1_2)); + T (S (2), alloc1 (r_1_2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc1 (r_2_3)); + T (S (2), alloc1 (r_2_3)); + T (S (3), alloc1 (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), alloc1 (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } +} + +NOIPA void test_strcpy_alloc2 (void) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + +#define alloc2(n) alloc2 (1, n) + + T (S (0), alloc1 (r_0_1)); + T (S (1), alloc1 (r_0_1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc1 (r_1_2)); + T (S (1), alloc1 (r_1_2)); + T (S (2), alloc1 (r_1_2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc1 (r_2_3)); + T (S (2), alloc1 (r_2_3)); + T (S (3), alloc1 (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), alloc1 (r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } +} + + +NOIPA void test_strcpy_alloc2_4 (void) +{ + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + +#define alloc2_4(n1, n2) alloc2_4 (1, n1, 2, n2) + + T (S (0), alloc2_4 (r_1_2, 1)); + T (S (1), alloc2_4 (r_1_2, 1)); + T (S (2), alloc2_4 (r_1_2, 1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (2), alloc2_4 (r_2_3, 1)); + T (S (3), alloc2_4 (r_2_3, 1)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc2_4 (1, r_1_2)); + T (S (1), alloc2_4 (1, r_1_2)); + T (S (2), alloc2_4 (1, r_1_2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (2), alloc2_4 (1, r_2_3)); + T (S (3), alloc2_4 (1, r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc2_4 (r_1_2, 2)); + T (S (1), alloc2_4 (r_1_2, 2)); + T (S (2), alloc2_4 (r_1_2, 2)); + T (S (3), alloc2_4 (r_1_2, 2)); + T (S (4), alloc2_4 (r_1_2, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc2_4 (r_2_3, 2)); + T (S (1), alloc2_4 (r_2_3, 2)); + T (S (2), alloc2_4 (r_2_3, 2)); + T (S (5), alloc2_4 (r_2_3, 2)); + T (S (6), alloc2_4 (r_2_3, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc2_4 (r_1_2, 2)); + T (S (1), alloc2_4 (r_1_2, 2)); + T (S (2), alloc2_4 (r_1_2, 2)); + T (S (3), alloc2_4 (r_1_2, 2)); + T (S (4), alloc2_4 (r_1_2, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc2_4 (r_2_3, 2)); + T (S (1), alloc2_4 (r_2_3, 2)); + T (S (2), alloc2_4 (r_2_3, 2)); + T (S (5), alloc2_4 (r_2_3, 2)); + T (S (6), alloc2_4 (r_2_3, 2)); // { dg-warning "\\\[-Wstringop-overflow" } + + T (S (0), alloc2_4 (r_1_2, r_2_3)); + T (S (1), alloc2_4 (r_1_2, r_2_3)); + T (S (2), alloc2_4 (r_1_2, r_2_3)); + T (S (3), alloc2_4 (r_1_2, r_2_3)); + T (S (4), alloc2_4 (r_1_2, r_2_3)); + T (S (5), alloc2_4 (r_1_2, r_2_3)); + T (S (6), alloc2_4 (r_1_2, r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + T (S (9), alloc2_4 (r_1_2, r_2_3)); // { dg-warning "\\\[-Wstringop-overflow" } + + size_t r_2_dmax = UR (2, DIFF_MAX); + T (S (0), alloc2_4 (r_2_dmax, r_2_dmax)); + T (S (9), alloc2_4 (r_2_dmax, r_2_dmax)); + + size_t r_2_smax = UR (2, SIZE_MAX); + T (S (0), alloc2_4 (r_2_smax, r_2_smax)); + T (S (9), alloc2_4 (r_2_smax, r_2_smax)); +} + +#undef T +#define T(T, src, n) do { \ + char *s = src; \ + T vla[n]; \ + char *d = (char*)vla; \ + strcpy (d, s); \ + sink (vla); \ + } while (0) + +NOIPA void test_strcpy_vla (void) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (char, S (0), r_0_1); + T (char, S (1), r_0_1); // { dg-warning "\\\[-Wstringop-overflow" } + + T (char, S (0), r_1_2); + T (char, S (1), r_1_2); + T (char, S (2), r_1_2); // { dg-warning "\\\[-Wstringop-overflow" } + + T (char, S (0), r_2_3); + T (char, S (2), r_2_3); + T (char, S (3), r_2_3); // { dg-warning "\\\[-Wstringop-overflow" } + T (char, S (9), r_2_3); // { dg-warning "\\\[-Wstringop-overflow" } + +#ifdef __INT16_TYPE__ + typedef __INT16_TYPE__ int16_t; + + T (int16_t, S (0), r_1_2); + T (int16_t, S (2), r_1_2); + T (int16_t, S (3), r_1_2); + T (int16_t, S (4), r_1_2); // { dg-warning "\\\[-Wstringop-overflow" } + T (int16_t, S (5), r_1_2); // { dg-warning "\\\[-Wstringop-overflow" } + T (int16_t, S (9), r_1_2); // { dg-warning "\\\[-Wstringop-overflow" } + + T (int16_t, S (0), r_2_3); + T (int16_t, S (2), r_2_3); + T (int16_t, S (3), r_2_3); + T (int16_t, S (4), r_2_3); + T (int16_t, S (5), r_2_3); + T (int16_t, S (6), r_2_3); // { dg-warning "\\\[-Wstringop-overflow" } +#endif + +#ifdef __INT32_TYPE__ + typedef __INT32_TYPE__ int32_t; + + T (int32_t, S ( 0), r_2_3); + T (int32_t, S ( 2), r_2_3); + T (int32_t, S ( 3), r_2_3); + T (int32_t, S ( 4), r_2_3); + T (int32_t, S ( 5), r_2_3); + T (int32_t, S ( 6), r_2_3); + T (int32_t, S (11), r_2_3); + T (int32_t, S (12), r_2_3); // { dg-warning "\\\[-Wstringop-overflow" } + T (int32_t, S (36), r_2_3); // { dg-warning "\\\[-Wstringop-overflow" } +#endif +} + + +struct Flex +{ + char n, ax[]; +}; + +#undef T +#define T(T, src, n) do { \ + char *s = src; \ + typedef struct { T n, ax[]; } Flex; \ + Flex *p = (Flex*)malloc (sizeof *p + n); \ + char *d = (char*)p->ax; \ + strcpy (d, s); \ + sink (p); \ + } while (0) + +NOIPA void test_strcpy_malloc_flexarray (void) +{ + size_t r_0_1 = UR (0, 1); + size_t r_1_2 = UR (1, 2); + size_t r_2_3 = UR (2, 3); + + T (char, S (0), r_0_1); + T (char, S (1), r_0_1); // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } } + + T (char, S (0), r_1_2); + T (char, S (1), r_1_2); + T (char, S (2), r_1_2); // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } } + + T (char, S (0), r_2_3); + T (char, S (2), r_2_3); + T (char, S (3), r_2_3); // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } } + T (char, S (9), r_2_3); // { dg-warning "\\\[-Wstringop-overflow" "pr92814" { xfail *-*-* } } +} diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size.c b/gcc/testsuite/gcc.dg/attr-alloc_size.c index 88a77715805..7b0dc6e4535 100644 --- a/gcc/testsuite/gcc.dg/attr-alloc_size.c +++ b/gcc/testsuite/gcc.dg/attr-alloc_size.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ +/* { dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */ extern void abort (void); diff --git a/gcc/testsuite/gcc.dg/attr-copy-2.c b/gcc/testsuite/gcc.dg/attr-copy-2.c index 8564811fc0b..f311ca32aa6 100644 --- a/gcc/testsuite/gcc.dg/attr-copy-2.c +++ b/gcc/testsuite/gcc.dg/attr-copy-2.c @@ -2,7 +2,7 @@ Exercise attribute copy for functions. { dg-do compile } { dg-require-alias "" } - { dg-options "-O2 -Wall" } */ + { dg-options "-O2 -Wall -Wno-array-bounds" } */ #define Assert(expr) typedef char AssertExpr[2 * !!(expr) - 1] diff --git a/gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c b/gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c index 489f88077d4..320cd51fcf2 100644 --- a/gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c +++ b/gcc/testsuite/gcc.dg/builtin-stringop-chk-5.c @@ -1,4 +1,4 @@ -/* Test exercising -Wrawmem-overflow and -Wstringop-overflow warnings. */ +/* Test exercising -Wstringop-overflow warnings. */ /* { dg-do compile } */ /* { dg-options "-O2 -Wstringop-overflow=1" } */ @@ -49,7 +49,7 @@ void test_memop_warn_local (const void *src) memcpy (a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */ escape (a, src); - /* At -Wrawmem-overflow=1 the destination is considered to be + /* At -Wstringop-overflow=1 the destination is considered to be the whole array and its size is therefore sizeof a. */ memcpy (&a[0], src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" } */ escape (a, src); @@ -110,12 +110,12 @@ void test_memop_warn_alloc (const void *src) struct A *a = __builtin_malloc (sizeof *a * 2); - memcpy (a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */ + memcpy (a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" } */ escape (a, src); - /* At -Wrawmem-overflow=1 the destination is considered to be + /* At -Wstringop-overflow=1 the destination is considered to be the whole array and its size is therefore sizeof a. */ - memcpy (&a[0], src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */ + memcpy (&a[0], src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 overflows the destination" "memcpy into allocated" } */ escape (a, src); /* Verify the same as above but by writing into the first mmeber @@ -127,7 +127,7 @@ void test_memop_warn_alloc (const void *src) struct B *b = __builtin_malloc (sizeof *b * 2); - memcpy (&b[0], src, n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 overflows the destination" "memcpy into allocated" { xfail *-*-*} } */ + memcpy (&b[0], src, n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 overflows the destination" "memcpy into allocated" } */ escape (b); /* The following idiom of clearing multiple members of a struct is diff --git a/gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c b/gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c index f4056f3632b..741c1f88eaa 100644 --- a/gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c +++ b/gcc/testsuite/gcc.dg/builtin-stringop-chk-8.c @@ -102,9 +102,9 @@ void test_memop_warn_alloc (void *p) struct A *a = __builtin_malloc (sizeof *a * 2); - memcpy (p, a, n); /* { dg-warning "reading between 8 and 32 bytes from region of size 4" "memcpy from allocated" { xfail *-*-*} } */ + memcpy (p, a, n); /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" } */ - memcpy (p, &a[0], n); /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" { xfail *-*-*} } */ + memcpy (p, &a[0], n); /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" } */ memcpy (p, &a[0].a, n); /* { dg-warning "reading between 8 and 32 bytes from a region of size 4" "memcpy from allocated" { xfail *-*-*} } */ @@ -112,13 +112,13 @@ void test_memop_warn_alloc (void *p) struct B *b = __builtin_malloc (sizeof *b * 2); - memcpy (p, &b[0], n); /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" "memcpy from allocated" { xfail *-*-*} } */ + memcpy (p, &b[0], n); /* { dg-warning "reading between 12 and 32 bytes from a region of size 8" "memcpy from allocated" } */ /* Verify memchr/memcmp. */ n = sizeof *b * 2 + 1; - memchr (b, 1, n); /* { dg-warning "reading 5 bytes from a region of size 4" "memcmp from allocated" { xfail *-*-* } } */ - memcmp (p, b, n); /* { dg-warning "reading 5 bytes from a region of size 4" "memcmp from allocated" { xfail *-*-* } } */ + memchr (b, 1, n); /* { dg-warning "reading 9 bytes from a region of size 8" "memcmp from allocated" } */ + memcmp (p, b, n); /* { dg-warning "reading 9 bytes from a region of size 8" "memcmp from allocated" } */ } diff --git a/gcc/testsuite/gcc.target/i386/pr82002-2a.c b/gcc/testsuite/gcc.target/i386/pr82002-2a.c index c31440debe2..dbcc105fcd2 100644 --- a/gcc/testsuite/gcc.target/i386/pr82002-2a.c +++ b/gcc/testsuite/gcc.target/i386/pr82002-2a.c @@ -10,3 +10,5 @@ b () a (c); a (c); } + +/* { dg-prune-output "\\\[-Wstringop-overflow" } */ diff --git a/gcc/testsuite/gcc.target/i386/pr82002-2b.c b/gcc/testsuite/gcc.target/i386/pr82002-2b.c index 939e069517d..e1ad737263c 100644 --- a/gcc/testsuite/gcc.target/i386/pr82002-2b.c +++ b/gcc/testsuite/gcc.target/i386/pr82002-2b.c @@ -10,3 +10,5 @@ b () a (c); a (c); } + +/* { dg-prune-output "\\\[-Wstringop-overflow" } */ diff --git a/gcc/tree-ssa-strlen.c b/gcc/tree-ssa-strlen.c index d46586a90e5..beff17b37f1 100644 --- a/gcc/tree-ssa-strlen.c +++ b/gcc/tree-ssa-strlen.c @@ -4394,8 +4394,22 @@ handle_store (gimple_stmt_iterator *gsi, bool *zero_write, const vr_values *rval stmt, lenrange[2], dstsize)) { if (decl) - inform (DECL_SOURCE_LOCATION (decl), - "destination object declared here"); + { + if (TREE_CODE (decl) == SSA_NAME) + { + gimple *stmt = SSA_NAME_DEF_STMT (decl); + if (is_gimple_call (stmt)) + { + tree allocfn = gimple_call_fndecl (stmt); + inform (gimple_location (stmt), + "destination region allocated by %qD " + "here", allocfn); + } + } + else + inform (DECL_SOURCE_LOCATION (decl), + "destination object declared here"); + } gimple_set_no_warning (stmt, true); } } -- 2.30.2