PR middle-end/91582 - missing heap overflow detection for strcpy
PR middle-end/91582 - missing heap overflow detection for strcpy PR middle-end/92868 - ICE: tree check: expected integer_cst, have ssa_name gcc/ChangeLog: PR middle-end/91582 PR middle-end/92868 * builtins.c (addr_decl_size): New function. (gimple_call_alloc_size): Add arguments. (compute_objsize): Add an argument. Set *PDECL even for allocated objects. Correct checking for negative wide_int. Correct handling of negative outer offsets into unknown regions or with unknown inner offsets. Extend offsets to at most sizetype precision. Only handle constant subobject sizes. * builtins.h (gimple_call_alloc_size): Add arguments. * tree.c (component_ref_size): Always return sizetype. * tree-ssa-strlen.c (strinfo::alloc): New member. (get_addr_stridx): Add argument. (get_stridx): Use ptrdiff_t. Add argument. (new_strinfo): Set new member. (get_string_length): Handle alloca and VLA. (dump_strlen_info): Dump more state. (maybe_invalidate): Print more info. Decrease indentation. (unshare_strinfo): Set new member. (valid_builtin_call): Handle alloca and VLA. (maybe_warn_overflow): Check and set no-warning bit. Improve handling of offsets. Print allocated objects. (handle_builtin_strlen): Handle strinfo records with null lengths. (handle_builtin_strcpy): Add argument. Call maybe_warn_overflow. (is_strlen_related_p): Handle dynamically allocated objects. (get_range): Add argument. (handle_builtin_malloc): Rename... (handle_alloc): ...to this and handle all allocation functions. (handle_builtin_memset): Call maybe_warn_overflow. (count_nonzero_bytes): Handle more MEM_REF forms. (strlen_check_and_optimize_call): Call handle_alloc_call. Pass arguments to more callees. (handle_integral_assign): Add argument. Create strinfo entries for MEM_REF assignments. (check_and_optimize_stmt): Handle more MEM_REF forms. gcc/testsuite/ChangeLog: PR middle-end/91582 * c-c++-common/Wrestrict.c: Adjust expected warnings. * gcc/testsuite/c-c++-common/Wstringop-truncation-4.c: Enable more warnings. * gcc/testsuite/c-c++-common/Wstringop-truncation.c: Remove an xfail. * gcc.dg/Warray-bounds-46.c: Disable -Wstringop-overflow. * gcc.dg/Warray-bounds-47.c: Same. * gcc.dg/Warray-bounds-52.c: New test. * gcc.dg/Wstringop-overflow-27.c: New test. * gcc.dg/Wstringop-overflow-28.c: New test. * gcc.dg/Wstringop-overflow-29.c: New test. * gcc.dg/attr-alloc_size.c (test): Disable -Warray-bounds. * gcc.dg/attr-copy-2.c: Adjust expected warnings. * gcc.dg/builtin-stringop-chk-5.c: Adjust text of expected messages. * gcc.dg/strlenopt-86.c: Relax test. * gcc.target/i386/pr82002-1.c: Prune expected warnings. From-SVN: r279392
This commit is contained in:
parent
e78b9a6fca
commit
ef29b12cfb
@ -1,3 +1,43 @@
|
||||
2019-12-13 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/91582
|
||||
PR middle-end/92868
|
||||
* builtins.c (addr_decl_size): New function.
|
||||
(gimple_call_alloc_size): Add arguments.
|
||||
(compute_objsize): Add an argument. Set *PDECL even for allocated
|
||||
objects.
|
||||
Correct checking for negative wide_int.
|
||||
Correct handling of negative outer offsets into unknown regions
|
||||
or with unknown inner offsets.
|
||||
Extend offsets to at most sizetype precision.
|
||||
Only handle constant subobject sizes.
|
||||
* builtins.h (gimple_call_alloc_size): Add arguments.
|
||||
* tree.c (component_ref_size): Always return sizetype.
|
||||
* tree-ssa-strlen.c (strinfo::alloc): New member.
|
||||
(get_addr_stridx): Add argument.
|
||||
(get_stridx): Use ptrdiff_t. Add argument.
|
||||
(new_strinfo): Set new member.
|
||||
(get_string_length): Handle alloca and VLA.
|
||||
(dump_strlen_info): Dump more state.
|
||||
(maybe_invalidate): Print more info. Decrease indentation.
|
||||
(unshare_strinfo): Set new member.
|
||||
(valid_builtin_call): Handle alloca and VLA.
|
||||
(maybe_warn_overflow): Check and set no-warning bit. Improve
|
||||
handling of offsets. Print allocated objects.
|
||||
(handle_builtin_strlen): Handle strinfo records with null lengths.
|
||||
(handle_builtin_strcpy): Add argument. Call maybe_warn_overflow.
|
||||
(is_strlen_related_p): Handle dynamically allocated objects.
|
||||
(get_range): Add argument.
|
||||
(handle_builtin_malloc): Rename...
|
||||
(handle_alloc): ...to this and handle all allocation functions.
|
||||
(handle_builtin_memset): Call maybe_warn_overflow.
|
||||
(count_nonzero_bytes): Handle more MEM_REF forms.
|
||||
(strlen_check_and_optimize_call): Call handle_alloc_call. Pass
|
||||
arguments to more callees.
|
||||
(handle_integral_assign): Add argument. Create strinfo entries
|
||||
for MEM_REF assignments.
|
||||
(check_and_optimize_stmt): Handle more MEM_REF forms.
|
||||
|
||||
2019-12-13 Iain Sandoe <iain@sandoe.co.uk>
|
||||
|
||||
* config/rs6000/darwin.h (DARWIN_DYLIB1_SPEC): New.
|
||||
|
257
gcc/builtins.c
257
gcc/builtins.c
@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
|
||||
#include "calls.h"
|
||||
#include "varasm.h"
|
||||
#include "tree-object-size.h"
|
||||
#include "tree-ssa-strlen.h"
|
||||
#include "realmpfr.h"
|
||||
#include "cfgrtl.h"
|
||||
#include "except.h"
|
||||
@ -3696,11 +3697,13 @@ 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. */
|
||||
/* If STMT is a call to an allocation function, returns the constant
|
||||
size of the object allocated by the call represented as sizetype.
|
||||
If nonnull, sets RNG1[] to the range of the size. */
|
||||
|
||||
tree
|
||||
gimple_call_alloc_size (gimple *stmt)
|
||||
gimple_call_alloc_size (gimple *stmt, wide_int rng1[2] /* = NULL */,
|
||||
const vr_values *rvals /* = NULL */)
|
||||
{
|
||||
if (!stmt)
|
||||
return NULL_TREE;
|
||||
@ -3747,11 +3750,12 @@ gimple_call_alloc_size (gimple *stmt)
|
||||
|
||||
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)
|
||||
wide_int rng1_buf[2];
|
||||
/* If RNG1 is not set, use the buffer. */
|
||||
if (!rng1)
|
||||
rng1 = rng1_buf;
|
||||
|
||||
if (!get_range (size, rng1, rvals))
|
||||
return NULL_TREE;
|
||||
|
||||
if (argidx2 > nargs && TREE_CODE (size) == INTEGER_CST)
|
||||
@ -3761,20 +3765,18 @@ gimple_call_alloc_size (gimple *stmt)
|
||||
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)
|
||||
if (!get_range (n, rng2, rvals))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Extend to the maximum precsion to avoid overflow. */
|
||||
/* Extend to the maximum precision 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. */
|
||||
/* Compute products of both bounds for the caller but return the lesser
|
||||
of SIZE_MAX and the product of the upper bounds as a constant. */
|
||||
rng1[0] = rng1[0] * rng2[0];
|
||||
rng1[1] = rng1[1] * rng2[1];
|
||||
tree size_max = TYPE_MAX_VALUE (sizetype);
|
||||
@ -3787,36 +3789,76 @@ gimple_call_alloc_size (gimple *stmt)
|
||||
return wide_int_to_tree (sizetype, rng1[1]);
|
||||
}
|
||||
|
||||
/* Helper for compute_objsize. Returns the constant size of the DEST
|
||||
if it refers to a variable or field and sets *PDECL to the DECL and
|
||||
*POFF to zero. Otherwise returns null for other nodes. */
|
||||
|
||||
static tree
|
||||
addr_decl_size (tree dest, tree *pdecl, tree *poff)
|
||||
{
|
||||
if (TREE_CODE (dest) == ADDR_EXPR)
|
||||
dest = TREE_OPERAND (dest, 0);
|
||||
|
||||
if (DECL_P (dest))
|
||||
{
|
||||
*pdecl = dest;
|
||||
*poff = integer_zero_node;
|
||||
if (tree size = DECL_SIZE_UNIT (dest))
|
||||
return TREE_CODE (size) == INTEGER_CST ? size : NULL_TREE;
|
||||
}
|
||||
|
||||
if (TREE_CODE (dest) == COMPONENT_REF)
|
||||
{
|
||||
*pdecl = TREE_OPERAND (dest, 1);
|
||||
*poff = integer_zero_node;
|
||||
/* Only return constant sizes for now while callers depend on it. */
|
||||
if (tree size = component_ref_size (dest))
|
||||
return TREE_CODE (size) == INTEGER_CST ? size : NULL_TREE;
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* 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
|
||||
an estimate of the size of the object if successful or NULL when
|
||||
the size cannot be determined. When the referenced object involves
|
||||
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. Likewise,
|
||||
when POFF is nonnull *POFF is set to the offset into *PDECL.
|
||||
OSTYPE (only the least significant 2 bits are used).
|
||||
Returns an estimate of the size of the object represented as
|
||||
a sizetype constant if successful or NULL when the size cannot
|
||||
be determined.
|
||||
When the referenced object involves 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, sets *PDECL to the decl of the referenced 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 */,
|
||||
tree *poff /* = NULL */)
|
||||
tree *poff /* = NULL */, const vr_values *rvals /* = NULL */)
|
||||
{
|
||||
tree dummy_decl = NULL_TREE;
|
||||
if (!pdecl)
|
||||
pdecl = &dummy_decl;
|
||||
|
||||
tree dummy_off = size_zero_node;
|
||||
tree dummy_off = NULL_TREE;
|
||||
if (!poff)
|
||||
poff = &dummy_off;
|
||||
|
||||
unsigned HOST_WIDE_INT size;
|
||||
|
||||
/* Only the two least significant bits are meaningful. */
|
||||
ostype &= 3;
|
||||
|
||||
if (ostype)
|
||||
/* Except for overly permissive calls to memcpy and other raw
|
||||
memory functions with zero OSTYPE, detect the size from simple
|
||||
DECLs first to more reliably than compute_builtin_object_size
|
||||
set *PDECL and *POFF. */
|
||||
if (tree size = addr_decl_size (dest, pdecl, poff))
|
||||
return size;
|
||||
|
||||
unsigned HOST_WIDE_INT size;
|
||||
if (compute_builtin_object_size (dest, ostype, &size, pdecl, poff))
|
||||
return build_int_cst (sizetype, size);
|
||||
|
||||
@ -3826,8 +3868,15 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
|
||||
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);
|
||||
from its argument(s). If successful, also set *PDECL to
|
||||
DEST for the caller to include in diagnostics. */
|
||||
if (tree size = gimple_call_alloc_size (stmt))
|
||||
{
|
||||
*pdecl = dest;
|
||||
*poff = integer_zero_node;
|
||||
return size;
|
||||
}
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
if (!is_gimple_assign (stmt))
|
||||
@ -3853,17 +3902,21 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
|
||||
/* Ignore negative offsets for now. For others,
|
||||
use the lower bound as the most optimistic
|
||||
estimate of the (remaining) size. */
|
||||
if (wi::sign_mask (wioff))
|
||||
if (wi::neg_p (wioff))
|
||||
;
|
||||
else if (wi::ltu_p (wioff, wisiz))
|
||||
{
|
||||
*poff = size_binop (PLUS_EXPR, *poff, off);
|
||||
return wide_int_to_tree (TREE_TYPE (size),
|
||||
wi::sub (wisiz, wioff));
|
||||
}
|
||||
else
|
||||
{
|
||||
*poff = size_binop (PLUS_EXPR, *poff, off);
|
||||
if (*poff)
|
||||
{
|
||||
*poff = fold_convert (ptrdiff_type_node, *poff);
|
||||
off = fold_convert (ptrdiff_type_node, *poff);
|
||||
*poff = size_binop (PLUS_EXPR, *poff, off);
|
||||
}
|
||||
else
|
||||
*poff = off;
|
||||
if (wi::ltu_p (wioff, wisiz))
|
||||
return wide_int_to_tree (TREE_TYPE (size),
|
||||
wi::sub (wisiz, wioff));
|
||||
return size_zero_node;
|
||||
}
|
||||
}
|
||||
@ -3875,32 +3928,29 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
|
||||
enum value_range_kind rng = get_range_info (off, &min, &max);
|
||||
|
||||
if (rng == VR_RANGE)
|
||||
{
|
||||
if (tree size = compute_objsize (dest, ostype, pdecl))
|
||||
{
|
||||
wide_int wisiz = wi::to_wide (size);
|
||||
if (tree size = compute_objsize (dest, ostype, pdecl, poff))
|
||||
{
|
||||
wide_int wisiz = wi::to_wide (size);
|
||||
|
||||
/* Ignore negative offsets for now. For others,
|
||||
use the lower bound as the most optimistic
|
||||
estimate of the (remaining)size. */
|
||||
if (wi::sign_mask (min)
|
||||
|| wi::sign_mask (max))
|
||||
;
|
||||
else if (wi::ltu_p (min, wisiz))
|
||||
{
|
||||
*poff = size_binop (PLUS_EXPR, *poff,
|
||||
wide_int_to_tree (sizetype, min));
|
||||
/* Ignore negative offsets for now. For others,
|
||||
use the lower bound as the most optimistic
|
||||
estimate of the (remaining)size. */
|
||||
if (wi::neg_p (min) || wi::neg_p (max))
|
||||
;
|
||||
else
|
||||
{
|
||||
/* FIXME: For now, since the offset is non-constant,
|
||||
clear *POFF to keep it from being "misused."
|
||||
Eventually *POFF will need to become a range that
|
||||
can be properly added to the outer offset if it
|
||||
too is one. */
|
||||
*poff = NULL_TREE;
|
||||
if (wi::ltu_p (min, wisiz))
|
||||
return wide_int_to_tree (TREE_TYPE (size),
|
||||
wi::sub (wisiz, min));
|
||||
}
|
||||
else
|
||||
{
|
||||
*poff = size_binop (PLUS_EXPR, *poff,
|
||||
wide_int_to_tree (sizetype, min));
|
||||
return size_zero_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
return size_zero_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (code != ADDR_EXPR)
|
||||
@ -3926,10 +3976,25 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
|
||||
&& *poff && integer_zerop (*poff))
|
||||
return size_zero_node;
|
||||
|
||||
/* A valid offset into a declared object cannot be negative. */
|
||||
if (tree_int_cst_sgn (*poff) < 0)
|
||||
/* A valid offset into a declared object cannot be negative.
|
||||
A zero size with a zero "inner" offset is still zero size
|
||||
regardless of the "other" offset OFF. */
|
||||
if (*poff
|
||||
&& ((integer_zerop (*poff) && integer_zerop (size))
|
||||
|| (TREE_CODE (*poff) == INTEGER_CST
|
||||
&& tree_int_cst_sgn (*poff) < 0)))
|
||||
return size_zero_node;
|
||||
|
||||
wide_int offrng[2];
|
||||
if (!get_range (off, offrng, rvals))
|
||||
return NULL_TREE;
|
||||
|
||||
/* Convert to the same precision to keep wide_int from "helpfully"
|
||||
crashing whenever it sees other arguments. */
|
||||
const unsigned sizprec = TYPE_PRECISION (sizetype);
|
||||
offrng[0] = wide_int::from (offrng[0], sizprec, SIGNED);
|
||||
offrng[1] = wide_int::from (offrng[1], sizprec, SIGNED);
|
||||
|
||||
/* Adjust SIZE either up or down by the sum of *POFF and OFF
|
||||
above. */
|
||||
if (TREE_CODE (dest) == ARRAY_REF)
|
||||
@ -3938,29 +4003,35 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
|
||||
tree eltype = TREE_TYPE (dest);
|
||||
tree tpsize = TYPE_SIZE_UNIT (eltype);
|
||||
if (tpsize && TREE_CODE (tpsize) == INTEGER_CST)
|
||||
off = fold_build2 (MULT_EXPR, size_type_node, off, tpsize);
|
||||
{
|
||||
wide_int wsz = wi::to_wide (tpsize, offrng->get_precision ());
|
||||
offrng[0] *= wsz;
|
||||
offrng[1] *= wsz;
|
||||
}
|
||||
else
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
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 wisize = wi::to_wide (size);
|
||||
|
||||
if (!*poff)
|
||||
{
|
||||
wide_int min, max;
|
||||
enum value_range_kind rng
|
||||
= get_range_info (off, offrng, offrng + 1);
|
||||
if (rng != VR_RANGE)
|
||||
return NULL_TREE;
|
||||
/* If the "inner" offset is unknown and the "outer" offset
|
||||
is either negative or less than SIZE, return the size
|
||||
minus the offset. This may be overly optimistic in
|
||||
the first case if the inner offset happens to be less
|
||||
than the absolute value of the outer offset. */
|
||||
if (wi::neg_p (offrng[0]))
|
||||
return size;
|
||||
if (wi::ltu_p (offrng[0], wisize))
|
||||
return build_int_cst (sizetype, (wisize - offrng[0]).to_uhwi ());
|
||||
return size_zero_node;
|
||||
}
|
||||
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);
|
||||
offrng[0] = wide_int::from (offrng[0], sizprec, SIGNED);
|
||||
offrng[1] = wide_int::from (offrng[1], sizprec, SIGNED);
|
||||
|
||||
tree dstoff = *poff;
|
||||
if (integer_zerop (*poff))
|
||||
@ -3972,14 +4043,14 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
|
||||
*poff = size_binop (PLUS_EXPR, *poff, off);
|
||||
}
|
||||
|
||||
if (wi::sign_mask (offrng[0]) >= 0)
|
||||
if (!wi::neg_p (offrng[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);
|
||||
wide_int wisize = wi::to_wide (size, sizprec);
|
||||
if (wi::ltu_p (wisize, offrng[0]))
|
||||
return size_zero_node;
|
||||
|
||||
@ -3999,39 +4070,25 @@ compute_objsize (tree dest, int ostype, tree *pdecl /* = NULL */,
|
||||
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);
|
||||
dstoffrng[0] = wide_int::from (dstoffrng[0], sizprec, SIGNED);
|
||||
dstoffrng[1] = wide_int::from (dstoffrng[1], sizprec, SIGNED);
|
||||
|
||||
wide_int declsize = wi::to_wide (size);
|
||||
if (wi::sign_mask (dstoffrng[0]) > 0)
|
||||
declsize += dstoffrng[0];
|
||||
if (!wi::neg_p (dstoffrng[0]))
|
||||
wisize += dstoffrng[0];
|
||||
|
||||
offrng[1] += dstoffrng[1];
|
||||
if (wi::sign_mask (offrng[1]) < 0)
|
||||
if (wi::neg_p (offrng[1]))
|
||||
return size_zero_node;
|
||||
|
||||
return wide_int_to_tree (sizetype, declsize);
|
||||
return wide_int_to_tree (sizetype, wisize);
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
if (TREE_CODE (dest) == COMPONENT_REF)
|
||||
{
|
||||
*pdecl = TREE_OPERAND (dest, 1);
|
||||
return component_ref_size (dest);
|
||||
}
|
||||
|
||||
if (TREE_CODE (dest) != ADDR_EXPR)
|
||||
return NULL_TREE;
|
||||
|
||||
tree ref = TREE_OPERAND (dest, 0);
|
||||
if (DECL_P (ref))
|
||||
{
|
||||
*pdecl = ref;
|
||||
if (tree size = DECL_SIZE_UNIT (ref))
|
||||
return TREE_CODE (size) == INTEGER_CST ? size : NULL_TREE;
|
||||
}
|
||||
/* Try simple DECLs not handled above. */
|
||||
if (tree size = addr_decl_size (dest, pdecl, poff))
|
||||
return size;
|
||||
|
||||
tree type = TREE_TYPE (dest);
|
||||
if (TREE_CODE (type) == POINTER_TYPE)
|
||||
|
@ -133,8 +133,12 @@ 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 gimple_call_alloc_size (gimple *);
|
||||
extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL);
|
||||
|
||||
class vr_values;
|
||||
tree gimple_call_alloc_size (gimple *, wide_int[2] = NULL,
|
||||
const vr_values * = NULL);
|
||||
extern tree compute_objsize (tree, int, tree * = NULL, tree * = NULL,
|
||||
const vr_values * = NULL);
|
||||
|
||||
extern bool readonly_data_expr (tree exp);
|
||||
extern bool init_target_chars (void);
|
||||
|
@ -1,3 +1,22 @@
|
||||
2019-12-13 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/91582
|
||||
* c-c++-common/Wrestrict.c: Adjust expected warnings.
|
||||
* c-c++-common/Wstringop-truncation-4.c: Enable more
|
||||
warnings.
|
||||
* c-c++-common/Wstringop-truncation.c: Remove an xfail.
|
||||
* gcc.dg/Warray-bounds-46.c: Disable -Wstringop-overflow.
|
||||
* gcc.dg/Warray-bounds-47.c: Same.
|
||||
* gcc.dg/Warray-bounds-52.c: New test.
|
||||
* gcc.dg/Wstringop-overflow-27.c: New test.
|
||||
* gcc.dg/Wstringop-overflow-28.c: New test.
|
||||
* gcc.dg/Wstringop-overflow-29.c: New test.
|
||||
* gcc.dg/attr-alloc_size.c (test): Disable -Warray-bounds.
|
||||
* gcc.dg/attr-copy-2.c: Adjust expected warnings.
|
||||
* gcc.dg/builtin-stringop-chk-5.c: Adjust text of expected messages.
|
||||
* gcc.dg/strlenopt-86.c: Relax test.
|
||||
* gcc.target/i386/pr82002-1.c: Prune expected warnings.
|
||||
|
||||
2019-12-13 Roman Zhuykov <zhroma@ispras.ru>
|
||||
|
||||
PR rtl-optimization/92591
|
||||
|
@ -731,10 +731,16 @@ void test_strcpy_range (void)
|
||||
|
||||
r = SR (3, DIFF_MAX - 3);
|
||||
T (8, "01", a + r, a);
|
||||
T (8, "012", a + r, a); /* { dg-warning "accessing 4 bytes at offsets \\\[3, \[0-9\]+] and 0 may overlap 1 byte at offset 3" "strcpy" } */
|
||||
|
||||
/* The accesses below might trigger either
|
||||
-Wrestrict: accessing 4 bytes at offsets [3, \[0-9\]+] and 0 may overlap 1 byte at offset 3
|
||||
or
|
||||
-Wstringop-overflow: writing 4 bytes into a region of size 0
|
||||
Either of the two is appropriate. */
|
||||
T (8, "012", a + r, a); /* { dg-warning "\\\[-Wrestrict|-Wstringop-overflow" } */
|
||||
|
||||
r = SR (DIFF_MAX - 2, DIFF_MAX - 1);
|
||||
T (8, "012", a + r, a); /* { dg-warning "accessing 4 bytes at offsets \\\[\[0-9\]+, \[0-9\]+] and 0 overlaps" "strcpy" } */
|
||||
T (8, "012", a + r, a); /* { dg-warning "\\\[-Wrestrict|-Wstringop-overflow" } */
|
||||
|
||||
/* Exercise the full range of ptrdiff_t. */
|
||||
r = signed_value ();
|
||||
|
@ -21,9 +21,13 @@ struct Arrays
|
||||
|
||||
void test_arrays (struct Arrays *p, const char *s)
|
||||
{
|
||||
/* Expect accesses to all three arrays to trigger the warning,
|
||||
including the trailing one. The size argument is a good
|
||||
enough indication that it is not being used as a "legacy"
|
||||
flexible array member. */
|
||||
strncpy (p->a, s, sizeof p->a); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->b, s, sizeof p->b); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-bogus "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
}
|
||||
|
||||
struct Pointers
|
||||
@ -49,9 +53,11 @@ struct ConstArrays
|
||||
|
||||
void test_const_arrays (struct ConstArrays *p, const char *s)
|
||||
{
|
||||
/* Expect accesses to all three arrays to trigger the warning,
|
||||
including the trailing one. */
|
||||
strncpy ((char*)p->a, s, sizeof p->a); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->b, s, sizeof p->b); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-bogus "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
}
|
||||
|
||||
struct ConstPointers
|
||||
@ -77,9 +83,11 @@ struct VolatileArrays
|
||||
|
||||
void test_volatile_arrays (struct VolatileArrays *p, const char *s)
|
||||
{
|
||||
/* Expect accesses to all three arrays to trigger the warning,
|
||||
including the trailing one. */
|
||||
strncpy ((char*)p->a, s, sizeof p->a); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->b, s, sizeof p->b); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-bogus "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
}
|
||||
|
||||
struct VolatilePointers
|
||||
@ -105,9 +113,11 @@ struct ConstVolatileArrays
|
||||
|
||||
void test_const_volatile_arrays (struct ConstVolatileArrays *p, const char *s)
|
||||
{
|
||||
/* Expect accesses to all three arrays to trigger the warning,
|
||||
including the trailing one. */
|
||||
strncpy ((char*)p->a, s, sizeof p->a); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->b, s, sizeof p->b); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-bogus "\\\[-Wstringop-truncation" } */
|
||||
strncpy ((char*)p->c, s, sizeof p->c); /* { dg-warning "\\\[-Wstringop-truncation" } */
|
||||
}
|
||||
|
||||
struct ConstVolatilePointers
|
||||
|
@ -300,8 +300,7 @@ void test_strncpy_array (Dest *pd, int i, const char* s)
|
||||
CPY (pd->a5, s, 5); /* { dg-warning "specified bound 5 equals destination size" } */
|
||||
CPY (pd->a5, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" } */
|
||||
|
||||
/* The following is not yet handled. */
|
||||
CPY (pd->a5 + i, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" "member array" { xfail *-*-* } } */
|
||||
CPY (pd->a5 + i, s, sizeof pd->a5); /* { dg-warning "specified bound 5 equals destination size" "member array" } */
|
||||
|
||||
/* Verify that a copy that nul-terminates is not diagnosed. */
|
||||
CPY (pd->a5, "1234", sizeof pd->a5);
|
||||
|
@ -12,7 +12,7 @@ void sink (void*);
|
||||
struct Ax
|
||||
{
|
||||
char n;
|
||||
char a[]; // { dg-message "at offset \[0-2\] to object 'Ax::a' declared here" }
|
||||
char a[]; // { dg-message "at offset \[0-2\] to object 'Ax::a' declared here" "note: flexarray" }
|
||||
};
|
||||
|
||||
// Verify warning for a definition with no initializer.
|
||||
@ -93,7 +93,7 @@ NOIPA void gaxx ()
|
||||
struct A0
|
||||
{
|
||||
char n;
|
||||
char a[0]; // { dg-message "at offset \[0-2\] to object 'A0::a' with size 0 declared here" }
|
||||
char a[0]; // { dg-message "at offset \[0-2\] to object 'A0::a' with size 0 declared here" "note: trailing zero-length array" }
|
||||
};
|
||||
|
||||
// Verify warning for a definition with no initializer.
|
||||
@ -160,7 +160,7 @@ NOIPA void ga0x ()
|
||||
struct A1
|
||||
{
|
||||
char n;
|
||||
char a[1]; // { dg-message "at offset \[1-9\] to object 'A1::a' with size 1 declared here" }
|
||||
char a[1]; // { dg-message "at offset \[1-9\] to object 'A1::a' with size 1 declared here" "note: trailing one-element array" }
|
||||
};
|
||||
|
||||
// Verify warning for a definition with no initializer.
|
||||
@ -234,7 +234,7 @@ NOIPA void ga1x ()
|
||||
struct A1i
|
||||
{
|
||||
char n;
|
||||
char a[1]; // { dg-message "at offset \[1-9\] to object 'A1i::a' with size 1 declared here" }
|
||||
char a[1]; // { dg-message "at offset \[1-9\] to object 'A1i::a' with size 1 declared here" "note: interior one-element array" }
|
||||
char x;
|
||||
};
|
||||
|
||||
@ -307,7 +307,7 @@ NOIPA void ga1ix ()
|
||||
struct Bx
|
||||
{
|
||||
char n;
|
||||
char a[]; // { dg-message "at offset 0 to object 'Bx::a' declared here" }
|
||||
char a[]; // { dg-message "at offset 0 to object 'Bx::a' declared here" "note: flexarray class member" }
|
||||
|
||||
// Verify the warning for a constant.
|
||||
Bx () { a[0] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
@ -332,7 +332,7 @@ NOIPA void gbxi (int i)
|
||||
struct B0
|
||||
{
|
||||
char n;
|
||||
char a[0]; // { dg-message "at offset 0 to object 'B0::a' with size 0 declared here" }
|
||||
char a[0]; // { dg-message "at offset 0 to object 'B0::a' with size 0 declared here" "note: zero-length trailing array class member" }
|
||||
|
||||
B0 () { a[0] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
};
|
||||
@ -348,7 +348,7 @@ NOIPA void gb0 (void)
|
||||
struct B1
|
||||
{
|
||||
char n;
|
||||
char a[1]; // { dg-message "at offset 1 to object 'B1::a' with size 1 declared here" }
|
||||
char a[1]; // { dg-message "at offset 1 to object 'B1::a' with size 1 declared here" "note: one-element trailing array class member" }
|
||||
|
||||
B1 () { a[1] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
};
|
||||
@ -362,7 +362,7 @@ NOIPA void gb1 (void)
|
||||
|
||||
struct B123
|
||||
{
|
||||
char a[123]; // { dg-message "at offset 123 to object 'B123::a' with size 123 declared here" }
|
||||
char a[123]; // { dg-message "at offset 123 to object 'B123::a' with size 123 declared here" "note: large trailing array class member" }
|
||||
|
||||
B123 () { a[123] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
};
|
||||
@ -376,7 +376,7 @@ NOIPA void gb123 (void)
|
||||
|
||||
struct B234
|
||||
{
|
||||
char a[234]; // { dg-message "at offset 234 to object 'B234::a' with size 234 declared here" }
|
||||
char a[234]; // { dg-message "at offset 234 to object 'B234::a' with size 234 declared here" "note: large trailing array class member" }
|
||||
|
||||
B234 (int i) { a[i] = 0; } // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
};
|
||||
|
@ -3,7 +3,7 @@
|
||||
Test to verify that past-the-end accesses by string functions to member
|
||||
arrays by-reference objects are diagnosed.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -Wno-unused-local-typedefs -ftrack-macro-expansion=0" } */
|
||||
{ dg-options "-O2 -Wall -Wno-unused-local-typedefs -Wno-stringop-overflow -ftrack-macro-expansion=0" } */
|
||||
|
||||
#define SA(expr) typedef int StaticAssert [2 * !!(expr) - 1]
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
/* PR middle-end/91830 - Bogus -Warray-bounds on strcpy into a member
|
||||
of a subobject compiling binutils
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
|
||||
{ dg-options "-O2 -Wall -Wno-stringop-overflow -ftrack-macro-expansion=0" } */
|
||||
|
||||
extern char* strcpy (char*, const char*);
|
||||
extern void sink (void*);
|
||||
|
97
gcc/testsuite/gcc.dg/Warray-bounds-52.c
Normal file
97
gcc/testsuite/gcc.dg/Warray-bounds-52.c
Normal file
@ -0,0 +1,97 @@
|
||||
/* PR middle-end/92341 - missing -Warray-bounds indexing past the end
|
||||
of a compound literal
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */
|
||||
|
||||
#include "range.h"
|
||||
|
||||
#define INT_MAX __INT_MAX__
|
||||
#define INT_MIN (-__INT_MAX__ - 1)
|
||||
|
||||
void sink (int, ...);
|
||||
|
||||
|
||||
#define T(...) sink (__LINE__, (__VA_ARGS__))
|
||||
|
||||
|
||||
void direct_idx_cst (void)
|
||||
{
|
||||
T ((int[]){ }[-1]); // { dg-warning "array subscript -1 is outside array bounds of 'int\\\[0]'" }
|
||||
T ((int[]){ }[0]); // { dg-warning "array subscript 0 is outside array bounds of 'int\\\[0]'" }
|
||||
T ((int[]){ }[1]); // { dg-warning "array subscript 1 is outside array bounds of 'int\\\[0]'" }
|
||||
|
||||
T ((int[]){ 1 }[-1]); // { dg-warning "array subscript -1 is below array bounds of 'int\\\[1]'" }
|
||||
T ((int[]){ 1 }[0]);
|
||||
T ((int[]){ 1 }[1]); // { dg-warning "array subscript 1 is above array bounds of 'int\\\[1]'" }
|
||||
T ((int[]){ 1 }[INT_MIN]); // { dg-warning "array subscript -\[0-9\]+ is below array bounds of 'int\\\[1]'" }
|
||||
T ((int[]){ 1 }[INT_MAX]); // { dg-warning "array subscript \[0-9\]+ is above array bounds of 'int\\\[1]'" }
|
||||
T ((int[]){ 1 }[SIZE_MAX]); // { dg-warning "array subscript \[0-9\]+ is above array bounds of 'int\\\[1]'" }
|
||||
}
|
||||
|
||||
|
||||
void direct_idx_var (int i)
|
||||
{
|
||||
T ((char[]){ }[i]); // { dg-warning "array subscript i is outside array bounds of 'char\\\[0]'" }
|
||||
T ((int[]){ }[i]); // { dg-warning "array subscript i is outside array bounds of 'int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
void direct_idx_range (void)
|
||||
{
|
||||
ptrdiff_t i = SR (-2, -1);
|
||||
|
||||
T ((int[]){ 1 }[i]); // { dg-warning "array subscript \[ \n\r]+ is outside array bounds of 'int\\\[0]'" "pr?????" { xfail *-*-* } }
|
||||
}
|
||||
|
||||
|
||||
#undef T
|
||||
#define T(idx, ...) do { \
|
||||
int *p = (__VA_ARGS__); \
|
||||
sink (p[idx]); \
|
||||
} while (0)
|
||||
|
||||
void ptr_idx_cst (void)
|
||||
{
|
||||
T (-1, (int[]){ }); // { dg-warning "array subscript -1 is outside array bounds of 'int\\\[0]'" }
|
||||
T ( 0, (int[]){ }); // { dg-warning "array subscript 0 is outside array bounds of 'int\\\[0]'" }
|
||||
T (+1, (int[]){ }); // { dg-warning "array subscript 1 is outside array bounds of 'int\\\[0]'" }
|
||||
|
||||
T (-1, (int[]){ 1 }); // { dg-warning "array subscript -1 is outside array bounds of 'int\\\[1]'" }
|
||||
T ( 0, (int[]){ 1 });
|
||||
T (+1, (int[]){ 1 }); // { dg-warning "array subscript 1 is outside array bounds of 'int\\\[1]'" }
|
||||
T (INT_MIN, (int[]){ 1 }); // { dg-warning "array subscript -\[0-9\]+ is outside array bounds of 'int\\\[1]'" "lp64" { xfail ilp32 } }
|
||||
T (INT_MAX, (int[]){ 1 }); // { dg-warning "array subscript \[0-9\]+ is outside array bounds of 'int\\\[1]'" "lp64" { target lp64 } }
|
||||
// { dg-warning "array subscript -1 is outside array bounds of 'int\\\[1]'" "ilp32" { target ilp32 } .-1 }
|
||||
T (SIZE_MAX, (int[]){ 1 }); // { dg-warning "array subscript -?\[0-9\]+ is outside array bounds of 'int\\\[1]'" }
|
||||
}
|
||||
|
||||
|
||||
void ptr_idx_var (int i)
|
||||
{
|
||||
T (i, (int[]){ }); // { dg-warning "array subscript \[^\n\r\]+ is outside array bounds of 'int\\\[0]'" }
|
||||
T (i, (int[]){ 1 });
|
||||
T (i, (int[]){ i, 1 });
|
||||
}
|
||||
|
||||
void ptr_idx_range (void)
|
||||
{
|
||||
ptrdiff_t i = SR (-2, -1);
|
||||
|
||||
T (i, (int[]){ }); // { dg-warning "array subscript \\\[-2, -1] is outside array bounds of 'int\\\[0]'" }
|
||||
T (i, (int[]){ 1 }); // { dg-warning "array subscript \\\[-2, -1] is outside array bounds of 'int\\\[1]'" }
|
||||
T (i, (int[]){ i }); // { dg-warning "array subscript \\\[-2, -1] is outside array bounds of 'int\\\[1]'" }
|
||||
|
||||
i = SR (0, 1);
|
||||
|
||||
T (i, (int[]){ }); // { dg-warning "array subscript \\\[0, 1] is outside array bounds of 'int\\\[0]'" }
|
||||
T (i, (int[]){ 1 });
|
||||
|
||||
i = SR (1, 2);
|
||||
T (i, (int[]){ 1 }); // { dg-warning "array subscript \\\[1, 2] is outside array bounds of 'int\\\[1]'" }
|
||||
|
||||
i = SR (2, 3);
|
||||
T (i, (int[]){ 1, 2, 3 });
|
||||
|
||||
i = SR (3, 4);
|
||||
T (i, (int[]){ 2, 3, 4 }); // { dg-warning "array subscript \\\[3, 4] is outside array bounds of 'int\\\[3]'" }
|
||||
}
|
293
gcc/testsuite/gcc.dg/Wstringop-overflow-27.c
Normal file
293
gcc/testsuite/gcc.dg/Wstringop-overflow-27.c
Normal file
@ -0,0 +1,293 @@
|
||||
/* PR middle-end/91582 - missing heap overflow detection for strcpy
|
||||
PR middle-end/85484 - missing -Wstringop-overflow for strcpy with
|
||||
a string of non-const length
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -Wno-array-bounds" } */
|
||||
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
extern void* calloc (size_t, size_t);
|
||||
extern void* malloc (size_t);
|
||||
extern void* memcpy (void*, const void*, size_t);
|
||||
extern void* memset (void*, int, size_t);
|
||||
extern char* strcpy (char*, const char*);
|
||||
extern size_t strlen (const char*);
|
||||
|
||||
void sink (void*);
|
||||
|
||||
|
||||
void test_memcpy_nowarn (const void *s, int i, size_t n)
|
||||
{
|
||||
sink (memcpy (calloc (1, 1), s, 1));
|
||||
sink (memcpy (calloc (1, 2), s, 1));
|
||||
sink (memcpy (calloc (2, 1), s, 1));
|
||||
sink (memcpy (calloc (3, 1), s, 2));
|
||||
sink (memcpy (calloc (3, 1), "12", 2));
|
||||
sink (memcpy (calloc (3, 1), s, 3));
|
||||
sink (memcpy (calloc (3, 1), "12", 3));
|
||||
sink (memcpy (calloc (i, 1), s, 1));
|
||||
sink (memcpy (calloc (n, 1), s, 1));
|
||||
sink (memcpy (calloc (1, n), "", 1));
|
||||
sink (memcpy (calloc (1, i), "", 1));
|
||||
sink (memcpy (calloc (i, 1), "123", 3));
|
||||
sink (memcpy (calloc (n, 1), "123", 3));
|
||||
sink (memcpy (calloc (1, i), "123456", 7));
|
||||
sink (memcpy (calloc (1, n), "123456", 7));
|
||||
sink (memcpy (calloc (n, 1), s, 12345));
|
||||
sink (memcpy (calloc (1, n), s, n - 1));
|
||||
sink (memcpy (calloc (n, 1), s, n));
|
||||
|
||||
sink (memcpy ((char*)calloc (1, 1) + i, "123", 1));
|
||||
sink (memcpy ((char*)calloc (n, 1) + i, "123", n));
|
||||
|
||||
sink (memcpy ((char*)calloc (1, 1) + i, s, 1));
|
||||
sink (memcpy ((char*)calloc (n, 1) + i, s, n));
|
||||
|
||||
sink (memcpy (malloc (1), s, 1));
|
||||
sink (memcpy (malloc (2), s, 1));
|
||||
sink (memcpy (malloc (3), s, 2));
|
||||
sink (memcpy (malloc (3), "12", 2));
|
||||
sink (memcpy (malloc (3), s, 3));
|
||||
sink (memcpy (malloc (3), "12", 3));
|
||||
sink (memcpy (malloc (n), s, 1));
|
||||
sink (memcpy (malloc (n), "", 1));
|
||||
sink (memcpy (malloc (n), "123", 3));
|
||||
sink (memcpy (malloc (n), "123456", 7));
|
||||
sink (memcpy (malloc (n), s, 12345));
|
||||
sink (memcpy (malloc (n), s, n - 1));
|
||||
sink (memcpy (malloc (n), s, n));
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4 };
|
||||
void *p = (char*)malloc (sizeof a);
|
||||
memcpy (p, a, sizeof a);
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4, 5 };
|
||||
size_t nelts = sizeof a / sizeof *a;
|
||||
int vla[nelts];
|
||||
memcpy (vla, a, nelts * sizeof *vla);
|
||||
sink (vla);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_memcpy_warn (const int *s, size_t n)
|
||||
{
|
||||
{
|
||||
void *p = (char*)malloc (0);
|
||||
memcpy (p, s, 1); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = (char*)malloc (1);
|
||||
memcpy (p, s, 2); // { dg-warning "writing 2 bytes into a region of size 1" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = (char*)malloc (2);
|
||||
memcpy (p, s, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = (char*)malloc (3);
|
||||
memcpy (p, s, 4); // { dg-warning "writing 4 bytes into a region of size 3" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4 };
|
||||
void *p = (char*)malloc (sizeof *a);
|
||||
memcpy (p, a, sizeof a); // { dg-warning "" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4, 5 };
|
||||
size_t nelts = sizeof a / sizeof *a;
|
||||
char vla[nelts];
|
||||
memcpy (vla, a, nelts * sizeof *a); // { dg-warning "" }
|
||||
sink (vla);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = malloc (n);
|
||||
memcpy (p, s, n * sizeof *s); // { dg-warning "\\\[-Wstringop-overflow" "" { xfail *-*-* } }
|
||||
sink (p);
|
||||
}
|
||||
}
|
||||
|
||||
void test_memset_nowarn (int x, size_t n)
|
||||
{
|
||||
sink (memset (calloc (1, 1), x, 1));
|
||||
sink (memset (calloc (1, 2), x, 1));
|
||||
sink (memset (calloc (2, 1), x, 1));
|
||||
sink (memset (calloc (3, 1), x, 2));
|
||||
sink (memset (calloc (3, 1), x, 3));
|
||||
sink (memset (calloc (n, 1), x, 1));
|
||||
sink (memset (calloc (n, 1), x, 12345));
|
||||
sink (memset (calloc (1, n), x, n - 1));
|
||||
sink (memset (calloc (n, 1), x, n));
|
||||
|
||||
sink (memset (malloc (1), x, 1));
|
||||
sink (memset (malloc (2), x, 1));
|
||||
sink (memset (malloc (3), x, 2));
|
||||
sink (memset (malloc (3), x, 3));
|
||||
sink (memset (malloc (n), x, 1));
|
||||
sink (memset (malloc (n), x, 12345));
|
||||
sink (memset (malloc (n), x, n - 1));
|
||||
sink (memset (malloc (n), x, n));
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4 };
|
||||
void *p = (char*)malloc (sizeof a);
|
||||
memset (p, x, sizeof a);
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4, 5 };
|
||||
size_t nelts = sizeof a / sizeof *a;
|
||||
int vla[nelts];
|
||||
memset (vla, x, nelts * sizeof *vla);
|
||||
sink (vla);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_memset_warn (int x, size_t n)
|
||||
{
|
||||
{
|
||||
void *p = (char*)malloc (0);
|
||||
memset (p, x, 1); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = (char*)malloc (1);
|
||||
memset (p, x, 2); // { dg-warning "writing 2 bytes into a region of size 1" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = (char*)malloc (2);
|
||||
memset (p, x, 3); // { dg-warning "writing 3 bytes into a region of size 2" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = (char*)malloc (3);
|
||||
memset (p, x, 4); // { dg-warning "writing 4 bytes into a region of size 3" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4 };
|
||||
void *p = (char*)malloc (sizeof *a);
|
||||
memset (p, 0, sizeof a); // { dg-warning "" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
{
|
||||
const int a[] = { 1, 2, 3, 4, 5 };
|
||||
size_t nelts = sizeof a / sizeof *a;
|
||||
char vla[nelts];
|
||||
memset (vla, 0, nelts * sizeof *a); // { dg-warning "" }
|
||||
sink (vla);
|
||||
}
|
||||
|
||||
{
|
||||
void *p = malloc (n);
|
||||
memset (p, x, n * sizeof (int)); // { dg-warning "\\\[-Wstringop-overflow" "" { xfail *-*-* } }
|
||||
sink (p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_strcpy_nowarn (const char *s)
|
||||
{
|
||||
{
|
||||
const char a[] = "12";
|
||||
int n = strlen (a);
|
||||
char *t = (char*)calloc (2, n);
|
||||
strcpy (t, a);
|
||||
sink (t);
|
||||
}
|
||||
|
||||
{
|
||||
const char a[] = "123";
|
||||
unsigned n = strlen (a) + 1;
|
||||
char *t = (char*)calloc (n, 1);
|
||||
strcpy (t, a);
|
||||
sink (t);
|
||||
}
|
||||
|
||||
{
|
||||
const char a[] = "1234";
|
||||
size_t n = strlen (a) * 2;
|
||||
char *t = (char*)malloc (n);
|
||||
strcpy (t, a);
|
||||
sink (t);
|
||||
}
|
||||
|
||||
{
|
||||
const char a[] = "1234";
|
||||
size_t len = strlen (a) + 1;
|
||||
char vla[len];
|
||||
strcpy (vla, a);
|
||||
sink (vla);
|
||||
}
|
||||
|
||||
{
|
||||
size_t n = strlen (s) + 1;
|
||||
char *t = (char*)malloc (n);
|
||||
strcpy (t, s);
|
||||
sink (t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void test_strcpy_warn (const char *s)
|
||||
{
|
||||
{
|
||||
const char a[] = "123";
|
||||
/* Verify that using signed int for the strlen result works (i.e.,
|
||||
that the conversion from signed int to size_t doesn't prevent
|
||||
the detection. */
|
||||
int n = strlen (a);
|
||||
char *t = (char*)calloc (n, 1); // { dg-message "at offset 0 to an object with size 3 allocated by 'calloc' here" "calloc note" { xfail *-*-* } }
|
||||
// { dg-message "at offset 0 to an object with size at most 3 allocated by 'calloc' here" "calloc note" { target *-*-* } .-1 }
|
||||
strcpy (t, a); // { dg-warning "writing 4 bytes into a region of size (between 0 and )?3 " }
|
||||
|
||||
sink (t);
|
||||
}
|
||||
|
||||
{
|
||||
const char a[] = "1234";
|
||||
size_t n = strlen (a);
|
||||
char *t = (char*)malloc (n); // { dg-message "at offset 0 to an object with size 4 allocated by 'malloc' here" "malloc note" { xfail *-*-* } }
|
||||
// { dg-message "at offset 0 to an object with size at most 4 allocated by 'malloc' here" "malloc note" { target *-*-* } .-1 }
|
||||
strcpy (t, a); // { dg-warning "writing 5 bytes into a region of size (between 0 and )?4 " }
|
||||
sink (t);
|
||||
}
|
||||
|
||||
// Exercise PR middle-end/85484.
|
||||
{
|
||||
size_t len = strlen (s);
|
||||
char vla[len]; // { dg-message "at offset 0 to an object declared here" "vla note" }
|
||||
strcpy (vla, s); // { dg-warning "writing one too many bytes into a region of a size that depends on 'strlen'" }
|
||||
sink (vla);
|
||||
}
|
||||
|
||||
{
|
||||
size_t n = strlen (s);
|
||||
char *t = (char*)malloc (n); // { dg-message "at offset 0 to an object allocated by 'malloc' here" "malloc note" }
|
||||
strcpy (t, s); // { dg-warning "writing one too many bytes into a region of a size that depends on 'strlen'" }
|
||||
sink (t);
|
||||
}
|
||||
}
|
236
gcc/testsuite/gcc.dg/Wstringop-overflow-28.c
Normal file
236
gcc/testsuite/gcc.dg/Wstringop-overflow-28.c
Normal file
@ -0,0 +1,236 @@
|
||||
/* 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) char* alloc1 (size_t);
|
||||
extern ATTR (alloc_size (1, 2), malloc) char* alloc2 (size_t, size_t);
|
||||
|
||||
extern char* strcpy (char*, const char*);
|
||||
|
||||
void sink (void*, ...);
|
||||
|
||||
|
||||
/* Verify warning in stores to an object of variable size N in a known
|
||||
range, at an offset (N + I) with a constant I. */
|
||||
|
||||
void same_size_and_offset_idx_cst (void)
|
||||
{
|
||||
#define T(size, off, idx) do { \
|
||||
size_t n_ = size; \
|
||||
ptrdiff_t i_ = idx; \
|
||||
char *p_ = alloc1 (n_); \
|
||||
p_ += off; \
|
||||
p_[i_] = 0; \
|
||||
sink (p_); \
|
||||
} while (0)
|
||||
|
||||
{
|
||||
const size_t n = UR (2, 3);
|
||||
|
||||
T (n, n, -4); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[-2, -1] to an object with size between 2 and 3 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
T (n, n, -3);
|
||||
T (n, n, -2);
|
||||
T (n, n, -1);
|
||||
T (n, n, 0);
|
||||
T (n, n, 1); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[3, 4] to an object with size between 2 and 3 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
}
|
||||
|
||||
{
|
||||
const size_t n = UR (3, 4);
|
||||
|
||||
T (n, n, -5); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[-2, -1] to an object with size between 3 and 4 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
T (n, n, -4);
|
||||
T (n, n, -3);
|
||||
T (n, n, -2);
|
||||
T (n, n, -1);
|
||||
T (n, n, 0);
|
||||
T (n, n, 1); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[4, 5] to an object with size between 3 and 4 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
}
|
||||
|
||||
{
|
||||
const size_t n = UR (5, SIZE_MAX - 2);
|
||||
T (n, n, -1);
|
||||
T (n, n, -1);
|
||||
T (n, n, -1);
|
||||
T (n, n, -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Verify warning in stores to an object of variable size N in a known
|
||||
range, at an offset (M + I) with a variable M in some range and
|
||||
constant I. */
|
||||
|
||||
void different_size_and_offset_idx_cst (void)
|
||||
{
|
||||
{
|
||||
const size_t n = UR (2, 3);
|
||||
const size_t i = UR (1, 2);
|
||||
|
||||
T (n, i, -4); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[-3, -2] to an object with size between 2 and 3 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
T (n, i, -3); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[-2, -1] to an object with size between 2 and 3 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
T (n, i, -2);
|
||||
T (n, i, -1);
|
||||
T (n, i, 0);
|
||||
T (n, i, 1);
|
||||
T (n, i, 2); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[3, 4] to an object with size between 2 and 3 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
}
|
||||
|
||||
{
|
||||
const size_t n = UR (3, 4);
|
||||
const size_t i = UR (2, 5);
|
||||
|
||||
T (n, i, -6); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[-4, -1] to an object with size between 3 and 4 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
|
||||
/* The offsets -5 and -4 are both necessarily invalid even if the sum
|
||||
(i - 5) and (i - 4) are (or could be) in bounds because they imply
|
||||
that the intermediate offset (p + i) is out of bounds. */
|
||||
T (n, i, -5); // { dg-warning "" "intermediate offset" { xfail *-*-* } }
|
||||
T (n, i, -4); // { dg-warning "" "intermediate offset" { xfail *-*-* } }
|
||||
T (n, i, -3);
|
||||
T (n, i, -2);
|
||||
T (n, i, -1);
|
||||
T (n, i, 0);
|
||||
T (n, i, 1);
|
||||
T (n, i, 2); // { dg-warning "writing 1 byte into a region of size 0" }
|
||||
// { dg-message "at offset \\\[4, 7] to an object with size between 3 and 4 allocated by 'alloc1'" "note" { target *-*-* } .-1 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Verify warning in stores to an object of variable size N in a known
|
||||
range, at an offset (M + I) with a variable M in some range and
|
||||
constant I. */
|
||||
void different_size_and_offset_idx_var (void)
|
||||
{
|
||||
{
|
||||
const size_t n = UR (3, 4);
|
||||
const size_t i = UR (1, 2);
|
||||
|
||||
T (n, i, SR (DIFF_MIN, 0));
|
||||
T (n, i, SR ( -3, 0));
|
||||
T (n, i, SR ( -1, 0));
|
||||
T (n, i, SR ( 0, 1));
|
||||
T (n, i, SR ( 1, 2));
|
||||
T (n, i, SR ( 2, 3));
|
||||
/* The warning is issued below but the offset and the size in
|
||||
the note are wrong. See the FIXME in compute_objsize(). */
|
||||
T (n, i, SR ( 3, 4)); // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
// { dg-message "at offset 4 to an object with size between 3 and 4 allocated by 'alloc1'" "pr92940 note: offset addition" { xfail *-*-* } .-1 }
|
||||
// { dg-message "at offset . to an object with size . allocated by 'alloc1'" "note: offset addition" { target *-*-* } .-2 }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ptr_add_2 (int n, int i0, int i1)
|
||||
{
|
||||
if (n < 1 || 2 < n) n = 2;
|
||||
|
||||
if (i0 < 0 || 1 < i0) i0 = 0;
|
||||
if (i1 < 1 || 2 < i1) i1 = 1;
|
||||
|
||||
char *p = (char*)__builtin_malloc (n);
|
||||
char *q = p;
|
||||
|
||||
q += i0;
|
||||
q[0] = 0; // p[0]
|
||||
q += i1;
|
||||
q[0] = 1; // p[1]
|
||||
q[1] = 2; // p[2] // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
|
||||
sink (p, q);
|
||||
}
|
||||
|
||||
void ptr_add_3 (int n, int i0, int i1, int i2)
|
||||
{
|
||||
if (n < 3 || 4 < n) n = 3;
|
||||
|
||||
if (i0 < 0 || 1 < i0) i0 = 0;
|
||||
if (i1 < 1 || 2 < i1) i1 = 1;
|
||||
if (i2 < 2 || 3 < i2) i2 = 2;
|
||||
|
||||
char *p = (char*)__builtin_malloc (n);
|
||||
char *q = p;
|
||||
|
||||
q += i0;
|
||||
q[0] = 0; // p[0]
|
||||
q += i1;
|
||||
q[0] = 1; // p[1]
|
||||
q[1] = 2; // p[2]
|
||||
q += i2;
|
||||
q[0] = 3; // p[3]
|
||||
q[1] = 4; // p[4] // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
|
||||
sink (p, q);
|
||||
}
|
||||
|
||||
void ptr_add_4 (int n, int i0, int i1, int i2, int i3)
|
||||
{
|
||||
if (n < 7 || 8 < n) n = 7;
|
||||
|
||||
if (i0 < 0 || 1 < i0) i0 = 0;
|
||||
if (i1 < 1 || 2 < i1) i1 = 1;
|
||||
if (i2 < 2 || 3 < i2) i2 = 2;
|
||||
if (i3 < 3 || 4 < i3) i3 = 3;
|
||||
|
||||
char *p = (char*)__builtin_malloc (n);
|
||||
char *q = p;
|
||||
|
||||
q += i0;
|
||||
q[0] = 0; // p[0]
|
||||
q += i1;
|
||||
q[0] = 1; // p[1]
|
||||
q[1] = 2; // p[2]
|
||||
q += i2;
|
||||
q[0] = 3; // p[3]
|
||||
q[1] = 4; // p[4]
|
||||
q[2] = 5; // p[5]
|
||||
q += i3;
|
||||
q[0] = 6; // p[6]
|
||||
q[1] = 7; // p[7]
|
||||
q[2] = 8; // p[8] // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
|
||||
sink (p, q);
|
||||
}
|
||||
|
||||
void ptr_sub_from_end (int n, int i0, int i1, int i2, int i3)
|
||||
{
|
||||
if (n < 1 || 2 < n) n = 2;
|
||||
|
||||
char *p = (char*)__builtin_malloc (n);
|
||||
char *q = p;
|
||||
|
||||
// The following isn't diagnosed due to a bug/limitation.
|
||||
q += n; // N=1 N=2
|
||||
q[-1] = 0; // p[0] p[1]
|
||||
q[-2] = 1; // p[-1] p[0]
|
||||
q[-3] = 2; // p[-2] p[-1] // { dg-warning "\\\[-Wstringop-overflow" "pr92939: negative offset from end" { xfail *-*-* } }
|
||||
|
||||
/* The following isn't diagnosed because the warning doesn't recognize
|
||||
the index below as necessarily having the same value as the size
|
||||
argument to malloc. All it considers is the range. */
|
||||
q[0] = 2; // { dg-warning "\\\[-Wstringop-overflow" "pr92937: store just past the end" { xfail *-*-* } }
|
||||
q[1] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
|
||||
sink (p, q);
|
||||
}
|
66
gcc/testsuite/gcc.dg/Wstringop-overflow-29.c
Normal file
66
gcc/testsuite/gcc.dg/Wstringop-overflow-29.c
Normal file
@ -0,0 +1,66 @@
|
||||
/* PR middle-end/91582 - missing heap overflow detection for strcpy
|
||||
Verify calls via function pointers.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -Wno-array-bounds -ftrack-macro-expansion=0" } */
|
||||
|
||||
typedef __attribute__ ((alloc_size (1))) char* allocfn_t (unsigned);
|
||||
|
||||
extern allocfn_t allocfn;
|
||||
|
||||
void sink (void*);
|
||||
|
||||
void direct_call (void)
|
||||
{
|
||||
char *q = allocfn (0); // { dg-message "at offset 0 to an object with size 0 allocated by 'allocfn'" }
|
||||
q[0] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
sink (q);
|
||||
}
|
||||
|
||||
|
||||
void local_ptr_call (void)
|
||||
{
|
||||
allocfn_t *ptr = allocfn;
|
||||
char *q = ptr (1); // { dg-message "at offset -1 to an object with size 1 allocated by 'allocfn'" }
|
||||
q[0] = 0;
|
||||
q[-1] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
sink (q);
|
||||
}
|
||||
|
||||
|
||||
void global_ptr_call (void)
|
||||
{
|
||||
extern allocfn_t *ptralloc;
|
||||
|
||||
allocfn_t *ptr = ptralloc;
|
||||
char *q = ptr (2); // { dg-message "at offset 3 to an object with size 2 allocated by 'ptralloc'" }
|
||||
q[0] = 0;
|
||||
q[1] = 1;
|
||||
q[3] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
sink (q);
|
||||
}
|
||||
|
||||
void global_ptr_array_call (void)
|
||||
{
|
||||
extern allocfn_t * (arralloc[]);
|
||||
|
||||
allocfn_t *ptr = arralloc[0];
|
||||
char *q = ptr (2); // { dg-message "at offset 3 to an object with size 2 allocated by 'ptr'" }
|
||||
q[0] = 1;
|
||||
q[1] = 2;
|
||||
q[3] = 3; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
sink (q);
|
||||
}
|
||||
|
||||
|
||||
struct S { allocfn_t *ptralloc; };
|
||||
|
||||
void member_ptr_call (struct S *p)
|
||||
{
|
||||
char *q = p->ptralloc (3); // { dg-message "at offset 5 to an object with size 3 allocated by 'ptralloc' here" }
|
||||
q[0] = 0;
|
||||
q[1] = 1;
|
||||
q[2] = 2;
|
||||
q[5] = 0; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
sink (q);
|
||||
}
|
||||
|
@ -22,15 +22,15 @@ test (void)
|
||||
strcpy (p, "Hello");
|
||||
p = malloc1 (6);
|
||||
strcpy (p, "Hello");
|
||||
strcpy (p, "Hello World"); /* { dg-warning "writing" "strcpy" } */
|
||||
strcpy (p, "Hello World"); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "strcpy" } */
|
||||
p = malloc2 (__INT_MAX__ >= 1700000 ? 424242 : __INT_MAX__ / 4, 6);
|
||||
strcpy (p, "World");
|
||||
strcpy (p, "Hello World"); /* { dg-warning "writing" "strcpy" } */
|
||||
strcpy (p, "Hello World"); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "strcpy" } */
|
||||
p = calloc1 (2, 5);
|
||||
strcpy (p, "World");
|
||||
strcpy (p, "Hello World"); /* { dg-warning "writing" "strcpy" } */
|
||||
strcpy (p, "Hello World"); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "strcpy" } */
|
||||
p = calloc2 (2, __INT_MAX__ >= 1700000 ? 424242 : __INT_MAX__ / 4, 5);
|
||||
strcpy (p, "World");
|
||||
strcpy (p, "Hello World"); /* { dg-warning "writing" "strcpy" } */
|
||||
strcpy (p, "Hello World"); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" "strcpy" } */
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,7 @@ void* xref12 (int);
|
||||
void* call_xref12 (void)
|
||||
{
|
||||
void *p = xref12 (3);
|
||||
__builtin___strcpy_chk (p, "123", __builtin_object_size (p, 0)); /* { dg-warning "\\\[-Wstringop-overflow=]" } */
|
||||
__builtin___strcpy_chk (p, "123", __builtin_object_size (p, 0)); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
|
||||
return p;
|
||||
}
|
||||
|
||||
@ -197,7 +197,7 @@ void* falias_malloc (void);
|
||||
void* call_falias_malloc (void)
|
||||
{
|
||||
char *p = falias_malloc ();
|
||||
__builtin___strcpy_chk (p, "123", __builtin_object_size (p, 0)); /* { dg-warning "\\\[-Wstringop-overflow=]" } */
|
||||
__builtin___strcpy_chk (p, "123", __builtin_object_size (p, 0)); /* { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" } */
|
||||
return p;
|
||||
}
|
||||
|
||||
|
@ -110,7 +110,7 @@ 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" } */
|
||||
memcpy (a, src, n); /* { dg-warning "writing between 8 and 32 bytes into a region of size 4 " "memcpy into allocated" } */
|
||||
escape (a, src);
|
||||
|
||||
/* At -Wstringop-overflow=1 the destination is considered to be
|
||||
@ -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" } */
|
||||
memcpy (&b[0], src, n); /* { dg-warning "writing between 12 and 32 bytes into a region of size 8 " "memcpy into allocated" } */
|
||||
escape (b);
|
||||
|
||||
/* The following idiom of clearing multiple members of a struct is
|
||||
|
@ -9,11 +9,11 @@
|
||||
unsigned n0, n1;
|
||||
|
||||
void*
|
||||
keep_strlen_calloc_store_cst_memset (unsigned a, unsigned b)
|
||||
keep_strlen_calloc_store_cst_memset (int i, unsigned a, unsigned b)
|
||||
{
|
||||
char *p = __builtin_calloc (a, 1);
|
||||
|
||||
p[1] = 'x';
|
||||
p[i] = 'x';
|
||||
|
||||
__builtin_memset (p, 0, b);
|
||||
|
||||
@ -23,11 +23,11 @@ keep_strlen_calloc_store_cst_memset (unsigned a, unsigned b)
|
||||
}
|
||||
|
||||
void*
|
||||
keep_strlen_calloc_store_var_memset (int x, unsigned a, unsigned b)
|
||||
keep_strlen_calloc_store_var_memset (int i, int x, unsigned a, unsigned b)
|
||||
{
|
||||
char *p = __builtin_calloc (a, 1);
|
||||
|
||||
p[1] = x;
|
||||
p[i] = x;
|
||||
|
||||
__builtin_memset (p, 0, b);
|
||||
|
||||
@ -37,11 +37,11 @@ keep_strlen_calloc_store_var_memset (int x, unsigned a, unsigned b)
|
||||
}
|
||||
|
||||
void*
|
||||
keep_strlen_calloc_store_memset_2 (int x, unsigned a, unsigned b, unsigned c)
|
||||
keep_strlen_calloc_store_memset_2 (int i, int x, unsigned a, unsigned b, unsigned c)
|
||||
{
|
||||
char *p = __builtin_calloc (a, 1);
|
||||
|
||||
p[1] = x;
|
||||
p[i] = x;
|
||||
__builtin_memset (p, 0, b);
|
||||
|
||||
n0 = __builtin_strlen (p);
|
||||
|
@ -10,3 +10,5 @@ b ()
|
||||
a (c);
|
||||
a (c);
|
||||
}
|
||||
|
||||
// { dg-prune-output "\\\[-Wstringop-overflow" }
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,8 +25,10 @@ extern bool is_strlen_related_p (tree, tree);
|
||||
extern bool maybe_diag_stxncpy_trunc (gimple_stmt_iterator, tree, tree);
|
||||
extern tree set_strlen_range (tree, wide_int, wide_int, tree = NULL_TREE);
|
||||
|
||||
struct c_strlen_data;
|
||||
class vr_values;
|
||||
extern tree get_range (tree, wide_int[2], const vr_values * = NULL);
|
||||
|
||||
struct c_strlen_data;
|
||||
extern void get_range_strlen_dynamic (tree , c_strlen_data *, const vr_values *);
|
||||
|
||||
/* APIs internal to strlen pass. Defined in in gimple-ssa-sprintf.c. */
|
||||
|
@ -13583,8 +13583,8 @@ get_initializer_for (tree init, tree decl)
|
||||
determine the size of an initialized flexible array member.
|
||||
If non-null, *INTERIOR_ZERO_LENGTH is set when REF refers to
|
||||
an interior zero-length array.
|
||||
Returns the size (which might be zero for an object with
|
||||
an uninitialized flexible array member) or null if the size
|
||||
Returns the size as sizetype (which might be zero for an object
|
||||
with an uninitialized flexible array member) or null if the size
|
||||
cannot be determined. */
|
||||
|
||||
tree
|
||||
@ -13733,7 +13733,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||
memsz64 -= baseoff;
|
||||
return wide_int_to_tree (TREE_TYPE (memsize), memsz64);
|
||||
}
|
||||
return integer_zero_node;
|
||||
return size_zero_node;
|
||||
}
|
||||
|
||||
/* Return "don't know" for an external non-array object since its
|
||||
@ -13744,7 +13744,7 @@ component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||
&& DECL_EXTERNAL (base)
|
||||
&& (!typematch
|
||||
|| TREE_CODE (basetype) != ARRAY_TYPE)
|
||||
? NULL_TREE : integer_zero_node);
|
||||
? NULL_TREE : size_zero_node);
|
||||
}
|
||||
|
||||
/* Return the machine mode of T. For vectors, returns the mode of the
|
||||
|
Loading…
Reference in New Issue
Block a user