Commit 287ef129 by Martin Sebor Committed by Martin Sebor

PR tree-optimization/88771 - Misleading -Werror=array-bounds error

gcc/ChangeLog:

	PR tree-optimization/88771
	* gimple-ssa-warn-restrict.c (pass_wrestrict::gate): Also enable
	when -Wstringop-overflow is set.
	(builtin_memref::builtin_memref): Adjust excessive upper bound
	only when lower bound is not excessive.
	(maybe_diag_overlap): Detect and diagnose excessive bounds via
	-Wstringop-ovefflow.
	(maybe_diag_offset_bounds): Rename...
	(maybe_diag_access_bounds): ...to this.
	(check_bounds_or_overlap): Adjust for name change above.

gcc/testsuite/ChangeLog:

	PR tree-optimization/88771
	* gcc.dg/Wstringop-overflow-8.c: New test.
	* gcc.dg/Wstringop-overflow-9.c: New test.
	* gcc.dg/Warray-bounds-40.c: New test.
	* gcc.dg/builtin-stpncpy.c: Adjust.
	* gcc.dg/builtin-stringop-chk-4.c: Adjust.
	* g++.dg/opt/memcpy1.C: Adjust.

From-SVN: r268775
parent 28a8cef1
2019-02-11 Martin Sebor <msebor@redhat.com>
PR tree-optimization/88771
* gimple-ssa-warn-restrict.c (pass_wrestrict::gate): Also enable
when -Wstringop-overflow is set.
(builtin_memref::builtin_memref): Adjust excessive upper bound
only when lower bound is not excessive.
(maybe_diag_overlap): Detect and diagnose excessive bounds via
-Wstringop-ovefflow.
(maybe_diag_offset_bounds): Rename...
(maybe_diag_access_bounds): ...to this.
(check_bounds_or_overlap): Adjust for name change above.
2019-02-11 Martin Sebor <msebor@redhat.com>
PR c++/87996
* builtins.c (max_object_size): Move from here...
* builtins.h (max_object_size): ...and here...
......
......@@ -75,7 +75,7 @@ class pass_wrestrict : public gimple_opt_pass
bool
pass_wrestrict::gate (function *fun ATTRIBUTE_UNUSED)
{
return warn_array_bounds != 0 || warn_restrict != 0;
return warn_array_bounds || warn_restrict || warn_stringop_overflow;
}
/* Class to walk the basic blocks of a function in dominator order. */
......@@ -256,7 +256,7 @@ builtin_memref::builtin_memref (tree expr, tree size)
sizrange[1] = wi::to_offset (range[1]);
/* get_size_range returns SIZE_MAX for the maximum size.
Constrain it to the real maximum of PTRDIFF_MAX. */
if (sizrange[1] > maxobjsize)
if (sizrange[0] <= maxobjsize && sizrange[1] > maxobjsize)
sizrange[1] = maxobjsize;
}
else
......@@ -1567,18 +1567,56 @@ maybe_diag_overlap (location_t loc, gimple *call, builtin_access &acs)
return true;
}
/* Validate REF offsets in an expression passed as an argument to a CALL
to a built-in function FUNC to make sure they are within the bounds
of the referenced object if its size is known, or PTRDIFF_MAX otherwise.
Both initial values of the offsets and their final value computed by
the function by incrementing the initial value by the size are
/* Validate REF size and offsets in an expression passed as an argument
to a CALL to a built-in function FUNC to make sure they are within
the bounds of the referenced object if its size is known, or
PTRDIFF_MAX otherwise. DO_WARN is true when a diagnostic should
be issued, false otherwise.
Both initial values of the offsets and their final value computed
by the function by incrementing the initial value by the size are
validated. Return true if the offsets are not valid and a diagnostic
has been issued. */
has been issued, or would have been issued if DO_WARN had been true. */
static bool
maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict,
maybe_diag_access_bounds (location_t loc, gimple *call, tree func, int strict,
const builtin_memref &ref, bool do_warn)
{
const offset_int maxobjsize = tree_to_shwi (max_object_size ());
/* Check for excessive size first and regardless of warning options
since the result is used to make codegen decisions. */
if (ref.sizrange[0] > maxobjsize)
{
/* Return true without issuing a warning. */
if (!do_warn)
return true;
if (ref.ref && TREE_NO_WARNING (ref.ref))
return false;
if (warn_stringop_overflow)
{
if (EXPR_HAS_LOCATION (ref.ptr))
loc = EXPR_LOCATION (ref.ptr);
loc = expansion_point_location_if_in_system_header (loc);
if (ref.sizrange[0] == ref.sizrange[1])
return warning_at (loc, OPT_Wstringop_overflow_,
"%G%qD specified bound %wu "
"exceeds maximum object size %wu",
call, func, ref.sizrange[0].to_uhwi (),
maxobjsize.to_uhwi ());
return warning_at (loc, OPT_Wstringop_overflow_,
"%G%qD specified bound between %wu and %wu "
"exceeds maximum object size %wu",
call, func, ref.sizrange[0].to_uhwi (),
ref.sizrange[1].to_uhwi (),
maxobjsize.to_uhwi ());
}
}
/* Check for out-bounds pointers regardless of warning options since
the result is used to make codegen decisions. */
offset_int ooboff[] = { ref.offrange[0], ref.offrange[1] };
......@@ -1616,11 +1654,12 @@ maybe_diag_offset_bounds (location_t loc, gimple *call, tree func, int strict,
if (oobref == error_mark_node)
{
if (ref.sizrange[0] == ref.sizrange[1])
sprintf (rangestr[1], "%lli", (long long) ref.sizrange[0].to_shwi ());
sprintf (rangestr[1], "%llu",
(unsigned long long) ref.sizrange[0].to_shwi ());
else
sprintf (rangestr[1], "[%lli, %lli]",
(long long) ref.sizrange[0].to_shwi (),
(long long) ref.sizrange[1].to_shwi ());
(unsigned long long) ref.sizrange[0].to_uhwi (),
(unsigned long long) ref.sizrange[1].to_uhwi ());
tree type;
......@@ -1854,8 +1893,8 @@ check_bounds_or_overlap (gimple *call, tree dst, tree src, tree dstsize,
/* Validate offsets first to make sure they are within the bounds
of the destination object if its size is known, or PTRDIFF_MAX
otherwise. */
if (maybe_diag_offset_bounds (loc, call, func, strict, dstref, do_warn)
|| maybe_diag_offset_bounds (loc, call, func, strict, srcref, do_warn))
if (maybe_diag_access_bounds (loc, call, func, strict, dstref, do_warn)
|| maybe_diag_access_bounds (loc, call, func, strict, srcref, do_warn))
{
if (do_warn)
gimple_set_no_warning (call, true);
......
2019-02-11 Martin Sebor <msebor@redhat.com>
PR tree-optimization/88771
* gcc.dg/Wstringop-overflow-8.c: New test.
* gcc.dg/Wstringop-overflow-9.c: New test.
* gcc.dg/Warray-bounds-40.c: New test.
* gcc.dg/builtin-stpncpy.c: Adjust.
* gcc.dg/builtin-stringop-chk-4.c: Adjust.
* g++.dg/opt/memcpy1.C: Adjust.
2019-02-11 Martin Sebor <msebor@redhat.com>
PR c++/87996
* c-c++-common/array-5.c: New test.
* c-c++-common/pr68107.c: Adjust text of diagnostics.
......
......@@ -62,7 +62,7 @@ namespace CS
// OutV is initialized to SIZE_MAX in the ctor above causing
// the multiplication below to produce a very large number
// in excess of the maximum possible object size (SIZE_MAX/2).
__builtin_memcpy (this->OutP, InP, OutV * sizeof (csVector2)); // { dg-warning "specified size \[0-9\]+ exceeds maximum object size" }
__builtin_memcpy (this->OutP, InP, OutV * sizeof (csVector2)); // { dg-warning "exceeds maximum object size" }
return 0;
}
};
......
/* PR middle-end/88771 - Misleading -Werror=array-bounds error
Verify that the warning issued for calls to "bounded" string
functions when -Wstringop-overflow is disabled is -Warray-bounds
with the right wording.
{ dg-do compile }
{ dg-options "-O2 -Wall -Wno-stringop-overflow" } */
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define SIZE_MAX __SIZE_MAX__
typedef __SIZE_TYPE__ size_t;
extern void* memcpy (void*, const void*, size_t);
extern void* memmove (void*, const void*, size_t);
extern void* memset (void*, int, size_t);
extern char* stpncpy (char*, const char*, size_t);
extern char* strncat (char*, const char*, size_t);
extern char* strncpy (char*, const char*, size_t);
extern char* strndup (const char*, size_t);
extern int strncmp (const char*, const char*, size_t);
extern int strncasecmp (const char*, const char*, size_t);
extern size_t strnlen (const char*, size_t);
extern char *d;
extern const char *s;
void test_memcpy (void)
{
memcpy (d, s, SIZE_MAX); /* { dg-warning ".memcpy. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" } */
}
void test_memmove (void)
{
memmove (d, s, SIZE_MAX - 1); /* { dg-warning ".memmove. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" } */
}
void test_memset (void)
{
memset (d, 0, SIZE_MAX - 2); /* { dg-warning ".memset. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" "bug" { xfail *-*-* } } */
}
char* test_stpncpy (void)
{
return stpncpy (d, s, SIZE_MAX - 4); /* { dg-warning ".stpncpy. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" } */
}
void test_strncat (void)
{
strncat (d, s, SIZE_MAX - 3); /* { dg-warning ".strncat. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" } */
}
void test_strncpy (void)
{
strncpy (d, s, SIZE_MAX - 4); /* { dg-warning ".strncpy. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" } */
}
char* test_strndup (void)
{
return strndup (s, SIZE_MAX - 5); /* { dg-warning ".strndup. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" "bug" { xfail *-*-* } } */
}
size_t test_strnlen (void)
{
return strnlen (s, SIZE_MAX - 6); /* { dg-warning ".strnlen. pointer overflow between offset 0 and size \[0-9\]+ \\\[-Warray-bounds" "bug" { xfail *-*-* } } */
}
/* PR tree-optimization/79220 - missing -Wstringop-overflow= on a memcpy
overflow with a small power-of-2 size
{ dg-do compile }
{ dg-options "-O2 -Wno-array-bounds -Wstringop-overflow" } */
extern void* memcpy (void*, const void*, __SIZE_TYPE__);
extern void* memmove (void*, const void*, __SIZE_TYPE__);
extern void* memset (void*, int, __SIZE_TYPE__);
char d[1];
void test_memcpy_lit_2 (void)
{
memcpy (d, "01", 2); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memcpy_lit_4 (void)
{
memcpy (d, "0123", 4); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memmove_lit_8 (void)
{
memmove (d, "01234567", 8); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memcpy_ptr_2 (const void *s)
{
memcpy (d, s, 2); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memcpy_ptr_4 (const void *s)
{
memcpy (d, s, 4); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memcpy_ptr_8 (const void *s)
{
memcpy (d, s, 8); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memmove_ptr (const void *s)
{
memmove (d, s, 8); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memset_2 (void)
{
memset (d, 0, 2); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memset_4 (void)
{
memset (d, 0, 4); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
void test_memset_8 (void)
{
memset (d, 0, 8); /* { dg-warning "\\\[-Wstringop-overflow" } */
}
/* PR middle-end/88771 - Misleading -Werror=array-bounds error
Verify that the warning issued for calls to "bounded" string
functions is -Wstringop-overflow with the right wording.
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define SIZE_MAX __SIZE_MAX__
typedef __SIZE_TYPE__ size_t;
extern void* memcpy (void*, const void*, size_t);
extern void* memmove (void*, const void*, size_t);
extern void* memset (void*, int, size_t);
extern char* stpncpy (char*, const char*, size_t);
extern char* strncat (char*, const char*, size_t);
extern char* strncpy (char*, const char*, size_t);
extern char* strndup (const char*, size_t);
extern int strncmp (const char*, const char*, size_t);
extern int strncasecmp (const char*, const char*, size_t);
extern size_t strnlen (const char*, size_t);
extern char *d;
extern const char *s;
void test_memcpy (void)
{
memcpy (d, s, SIZE_MAX); /* { dg-warning ".memcpy. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
void test_memmove (void)
{
memmove (d, s, SIZE_MAX - 1); /* { dg-warning ".memmove. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
void test_memset (void)
{
memset (d, 0, SIZE_MAX - 2); /* { dg-warning ".memset. specified \(bound|size\) \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
char* test_stpncpy (void)
{
return stpncpy (d, s, SIZE_MAX - 4); /* { dg-warning ".stpncpy. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
void test_strncat (void)
{
strncat (d, s, SIZE_MAX - 3); /* { dg-warning ".strncat. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
void test_strncpy (void)
{
strncpy (d, s, SIZE_MAX - 4); /* { dg-warning ".strncpy. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
char* test_strndup (void)
{
return strndup (s, SIZE_MAX - 5); /* { dg-warning ".strndup. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
size_t test_strnlen (void)
{
return strnlen (s, SIZE_MAX - 6); /* { dg-warning ".strnlen. specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+ \\\[-Wstringop-overflow=\\\]" } */
}
......@@ -35,7 +35,7 @@ void test_cst (char *d)
__builtin_stpncpy (d, "123", n);
__builtin_stpncpy (d, "123", n + 1); /* { dg-warning "specified size \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
__builtin_stpncpy (d, "123", n + 1); /* { dg-warning "specified bound \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
}
......@@ -73,5 +73,5 @@ void test_rng (char *d)
__builtin_stpncpy (d, "123", R (n - 1, n + 1));
__builtin_stpncpy (d, "123", R (n + 1, n + 2)); /* { dg-warning "specified size between \[0-9\]+ and \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
__builtin_stpncpy (d, "123", R (n + 1, n + 2)); /* { dg-warning "specified bound between \[0-9\]+ and \[0-9\]+ exceeds maximum object size \[0-9\]+" } */
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment