mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-03-23 07:00:27 +08:00
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
This commit is contained in:
parent
a59c50bd14
commit
268209f3a0
@ -1,3 +1,14 @@
|
||||
2019-12-03 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
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 <julian@codesourcery.com>
|
||||
|
||||
* config/gcn/gcn.h (FIXED_REGISTERS): Make s6/s7 fixed registers.
|
||||
|
230
gcc/builtins.c
230
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;
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -1,3 +1,18 @@
|
||||
2019-12-03 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
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 <joseph@codesourcery.com>
|
||||
|
||||
PR c/36941
|
||||
|
@ -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" } */
|
||||
|
@ -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)))
|
||||
|
||||
|
157
gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C
Normal file
157
gcc/testsuite/g++.dg/warn/Wstringop-overflow-4.C
Normal file
@ -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
|
88
gcc/testsuite/gcc.dg/Warray-bounds-56.c
Normal file
88
gcc/testsuite/gcc.dg/Warray-bounds-56.c
Normal file
@ -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" }
|
||||
}
|
377
gcc/testsuite/gcc.dg/Wstringop-overflow-25.c
Normal file
377
gcc/testsuite/gcc.dg/Wstringop-overflow-25.c
Normal file
@ -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 *-*-* } }
|
||||
}
|
@ -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);
|
||||
|
||||
|
@ -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]
|
||||
|
||||
|
@ -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
|
||||
|
@ -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" } */
|
||||
}
|
||||
|
||||
|
||||
|
@ -10,3 +10,5 @@ b ()
|
||||
a (c);
|
||||
a (c);
|
||||
}
|
||||
|
||||
/* { dg-prune-output "\\\[-Wstringop-overflow" } */
|
||||
|
@ -10,3 +10,5 @@ b ()
|
||||
a (c);
|
||||
a (c);
|
||||
}
|
||||
|
||||
/* { dg-prune-output "\\\[-Wstringop-overflow" } */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user