Commit 3942060c by Martin Sebor

PR middle-end/94647 - bogus -Warray-bounds on strncpy into a larger member array…

PR middle-end/94647 - bogus -Warray-bounds on strncpy into a larger member array from a smaller array

gcc/ChangeLog:

	PR middle-end/94647
	* gimple-ssa-warn-restrict.c (builtin_access::builtin_access): Correct
	the computation of the lower bound of the source access size.
	(builtin_access::generic_overlap): Remove a hack for setting ranges
	of overlap offsets.

gcc/testsuite/ChangeLog:

	PR middle-end/94647
	* c-c++-common/Warray-bounds-2.c: Adjust a test case and add a new one.
	* c-c++-common/Warray-bounds-3.c: Add tests for missing warnings.
	* c-c++-common/Wrestrict.c: Invert bounds in printed ranges.
	* gcc.dg/Warray-bounds-59.c: New test.
	* gcc.dg/Wrestrict-10.c: Add a missing warning.
	* gcc.dg/Wrestrict-5.c: Adjust text of expected warning.
	* gcc.dg/Wrestrict-6.c: Expect to see a range of overlap offsets.
parent fb22faf4
2020-04-21 Martin Sebor <msebor@redhat.com>
PR middle-end/94647
* gimple-ssa-warn-restrict.c (builtin_access::builtin_access): Correct
the computation of the lower bound of the source access size.
(builtin_access::generic_overlap): Remove a hack for setting ranges
of overlap offsets.
2020-04-21 John David Anglin <danglin@gcc.gnu.org>
* config/pa/som.h (ASM_WEAKEN_LABEL): Delete.
......
......@@ -831,8 +831,8 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst,
}
else if (srcref->sizrange[0] == 0 && srcref->sizrange[1] == maxobjsize)
{
/* When the source size is unknown set it to the size of
the destination. */
/* When the size of the source access is unknown set it to the size
of the destination first and adjust it later if necessary. */
srcref->sizrange[0] = dstref->sizrange[0];
srcref->sizrange[1] = dstref->sizrange[1];
......@@ -842,15 +842,11 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst,
{
/* Read access by strncpy is constrained by the third
argument but except for a zero bound is at least one. */
offset_int size = wi::umax (srcref->basesize, 1);
offset_int bound = wi::umin (size, bounds[0]);
if (bound < srcref->sizrange[0])
srcref->sizrange[0] = bound;
bound = wi::umin (srcref->basesize, bounds[1]);
srcref->sizrange[0] = bounds[1] > 0 ? 1 : 0;
offset_int bound = wi::umin (srcref->basesize, bounds[1]);
if (bound < srcref->sizrange[1])
srcref->sizrange[1] = bound;
}
/* For string functions, adjust the size range of the source
reference by the inverse boundaries of the offset (because
the higher the offset into the string the shorter its
......@@ -859,7 +855,7 @@ builtin_access::builtin_access (gimple *call, builtin_memref &dst,
&& srcref->offrange[1] < srcref->sizrange[0])
srcref->sizrange[0] -= srcref->offrange[1];
else
srcref->sizrange[0] = 0;
srcref->sizrange[0] = 1;
if (srcref->offrange[0] > 0)
{
......@@ -1060,16 +1056,8 @@ builtin_access::generic_overlap ()
ovloff[0] = HOST_WIDE_INT_MAX;
ovloff[1] = HOST_WIDE_INT_MIN;
/* Adjustment to the lower bound of the offset of the overlap to
account for a subset of unbounded string calls where the size
of the destination string depends on the length of the source
which in turn depends on the offset into it. */
bool sub1;
if (stxcpy_p)
{
sub1 = acs.dstoff[0] <= acs.srcoff[0];
/* Iterate over the extreme locations (on the horizontal axis formed
by their offsets) and sizes of two regions and find their smallest
and largest overlap and the corresponding offsets. */
......@@ -1102,11 +1090,9 @@ builtin_access::generic_overlap ()
}
else
{
sub1 = !depends_p;
/* Iterate over the extreme locations (on the horizontal axis
formed by their offsets) and sizes of two regions and find
their smallest and largest overlap and the corresponding
formed by their offsets) and sizes of the two regions and
find their smallest and largest overlap and the corresponding
offsets. */
for (unsigned io = 0; io != 2; ++io)
......@@ -1119,15 +1105,6 @@ builtin_access::generic_overlap ()
for (unsigned jo = 0; jo != 2; ++jo)
for (unsigned js = 0; js != 2; ++js)
{
if (depends_p)
{
/* For st{p,r}ncpy the size of the source sequence
depends on the offset into it. */
if (js)
break;
js = !jo;
}
const offset_int b[2] = {
acs.srcoff[jo], acs.srcoff[jo] + acs.srcsiz[js]
};
......@@ -1154,8 +1131,9 @@ builtin_access::generic_overlap ()
ovlsiz[0] = siz[0].to_shwi ();
ovlsiz[1] = siz[1].to_shwi ();
/* Adjust the overlap offset range to reflect the overlap size range. */
if (ovlsiz[0] == 0 && ovlsiz[1] > 1)
ovloff[0] = ovloff[1] + ovlsiz[1] - 1 - sub1;
ovloff[1] = ovloff[0] + ovlsiz[1] - 1;
return true;
}
......
2020-04-21 Martin Sebor <msebor@redhat.com>
PR middle-end/94647
* c-c++-common/Warray-bounds-2.c: Adjust a test case and add a new one.
* c-c++-common/Warray-bounds-3.c: Add tests for missing warnings.
* c-c++-common/Wrestrict.c: Invert bounds in printed ranges.
* gcc.dg/Warray-bounds-59.c: New test.
* gcc.dg/Wrestrict-10.c: Add a missing warning.
* gcc.dg/Wrestrict-5.c: Adjust text of expected warning.
* gcc.dg/Wrestrict-6.c: Expect to see a range of overlap offsets.
2020-04-21 Szabolcs Nagy <szabolcs.nagy@arm.com>
PR target/94514
......
......@@ -172,14 +172,26 @@ void call_strncpy_src_xsize (char *d, size_t n)
/* Exercise strncpy out-of-bounds offsets with an array of unknown size. */
static void
wrap_strncpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
wrap_strncpy_src_diff_max_m1 (char *d, const char *s, ptrdiff_t i, size_t n)
{
/* Unlike in the similar call to memcpy(), there is no pointer
overflow here because the size N is not added to the source
offset. */
offset MAX - 1 (only 1 is for the access to its first element,
which is tested below). */
strncpy (d, s + i, n);
}
void call_strncpy_src_diff_max_m1 (char *d, const char *s, size_t n)
{
wrap_strncpy_src_diff_max_m1 (d, s, MAX - 1, 3);
}
static void
wrap_strncpy_src_diff_max (char *d, const char *s, ptrdiff_t i, size_t n)
{
strncpy (d, s + i, n); /* { dg-warning "pointer overflow between offset 9223372036854775807 and size \\\[1, 0]" } */
}
void call_strncpy_src_diff_max (char *d, const char *s, size_t n)
{
wrap_strncpy_src_diff_max (d, s, MAX, 3);
......
......@@ -287,15 +287,16 @@ void test_strcpy_bounds (char *d, const char *s)
TI (char, 1, "", a, a + SR (0, DIFF_MAX - 1));
TI (char, 2, "0", a, a + SR (0, DIFF_MAX - 1));
TI (char, 2, "0", a, a + SR (1, DIFF_MAX - 1));
/* The following needs a warning for reading past the end. */
TI (char, 2, "0", a, a + SR (2, DIFF_MAX - 1));
/* The warning below isn't the most accurate because while reading
from it is invalid, the offset that refers just past the end of
the source array is strictly valid. */
TI (char, 2, "0", a, a + SR (2, DIFF_MAX - 1)); /* { dg-warning "offset 2 is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type 'char ?\\\[2]'" } */
TI (char, 2, "0", a, a + SR (3, DIFF_MAX - 1)); /* { dg-warning "offset \\\[3, \[0-9\]+] is out of the bounds \\\[0, 2] of object \[^\n\r\]+ with type .char ?\\\[2\\\]." "strcpy" } */
TI (char, 3, "01", a, a + SR (0, DIFF_MAX - 1));
TI (char, 3, "01", a, a + SR (1, DIFF_MAX - 1));
TI (char, 3, "01", a, a + SR (2, DIFF_MAX - 1));
/* The following needs a warning for reading past the end. */
TI (char, 3, "01", a, a + SR (3, DIFF_MAX - 1));
TI (char, 3, "01", a, a + SR (3, DIFF_MAX - 1)); /* { dg-warning "offset 3 is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type 'char ?\\\[3]'" } */
TI (char, 3, "01", a, a + SR (4, DIFF_MAX - 1)); /* { dg-warning "offset \\\[4, \[0-9\]+] is out of the bounds \\\[0, 3] of object \[^\n\r\]+ with type .char ?\\\[3\\\]." "strcpy" } */
TI (char, 4, "012", a, a + SR (DIFF_MAX - 2, DIFF_MAX - 1)); /* { dg-warning "offset \\\[\[0-9\]+, \[0-9\]+] is out of the bounds \\\[0, 4] of object \[^\n\r\]+ with type .char ?\\\[4\\\]." "strcpy" } */
......
......@@ -684,7 +684,7 @@ void test_strcpy_range (void)
r = SR (2, 5);
T (8, "01", a + r, a); /* { dg-warning "accessing 3 bytes at offsets \\\[2, 5] and 0 may overlap 1 byte at offset 2" } */
T (8, "012", a + r, a); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 5] and 0 may overlap up to 2 bytes at offset \\\[3, 2]" "strcpy" } */
T (8, "012", a + r, a); /* { dg-warning "accessing 4 bytes at offsets \\\[2, 5] and 0 may overlap up to 2 bytes at offset \\\[2, 3]" "strcpy" } */
/* The highest offset to which to copy without overflowing the 8-byte
destination is 3 and that overlaps 2 bytes. */
......@@ -697,7 +697,7 @@ void test_strcpy_range (void)
/* With a 10-byte buffer it's possible to copy all 5 bytes without
overlap at (a + 5). Copying at offsets 2 through 4 overflows
between 3 and 1 bytes, respectively. */
T (10, "0123", a + r, a); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 5] and 0 may overlap up to 3 bytes at offset \\\[4, 2]" "strcpy" } */
T (10, "0123", a + r, a); /* { dg-warning "accessing 5 bytes at offsets \\\[2, 5] and 0 may overlap up to 3 bytes at offset \\\[2, 4]" "strcpy" } */
r = SR (3, 4);
......@@ -727,7 +727,7 @@ void test_strcpy_range (void)
overlap, so the warning is a "may overlap" and the size of
the overlap is 1 byte. */
T (8, "012345", a, a + r); /* { dg-warning "accessing between 3 and 4 bytes at offsets 0 and \\\[3, 4] may overlap 1 byte at offset 3" "strcpy" } */
T (8, "0123456", a, a + r); /* { dg-warning "accessing between 4 and 5 bytes at offsets 0 and \\\[3, 4] may overlap up to 2 bytes at offset 3" "strcpy" } */
T (8, "0123456", a, a + r); /* { dg-warning "accessing between 4 and 5 bytes at offsets 0 and \\\[3, 4] may overlap up to 2 bytes at offset \\\[3, 4]" "strcpy" } */
r = SR (3, DIFF_MAX - 3);
T (8, "01", a + r, a);
......@@ -752,8 +752,8 @@ void test_strcpy_range (void)
T (8, "012", a + r, a); /* { dg-warning "accessing 4 bytes at offsets \\\[0, 8] and 0 may overlap up to 4 bytes" "strcpy" } */
T (8, "", a, a + r); /* { dg-warning "accessing 1 byte at offsets 0 and \\\[0, 8] may overlap" "strcpy" } */
T (8, "0", a, a + r); /* { dg-warning "accessing between 0 and 2 bytes at offsets 0 and \\\[0, 8] may overlap up to 2 bytes" "strcpy" } */
T (8, "012", a, a + r); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[0, 8] may overlap up to 4 bytes" "strcpy" } */
T (8, "0", a, a + r); /* { dg-warning "accessing between 1 and 2 bytes at offsets 0 and \\\[0, 8] may overlap up to 2 bytes" "strcpy" } */
T (8, "012", a, a + r); /* { dg-warning "accessing between 1 and 4 bytes at offsets 0 and \\\[0, 8] may overlap up to 4 bytes" "strcpy" } */
}
/* Exercise strcpy with destination and/or source of unknown lengthu. */
......@@ -868,18 +868,21 @@ void test_strncpy_range (char *d, size_t n)
T ("0123", a, a + i, 0);
T ("0123", a, a + i, 1);
T ("0123", a, a + i, 2); /* { dg-warning "accessing 2 bytes at offsets 0 and \\\[1, 5] may overlap 1 byte at offset 1" "strncpy" } */
T ("0123", a, a + i, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and \\\[1, 5] may overlap up to 2 bytes at offset \\\[2, 1]" "strncpy" } */
T ("0123", a, a + i, 4); /* { dg-warning "accessing 4 bytes at offsets 0 and \\\[1, 5] may overlap up to 3 bytes at offset \\\[3, 1]" "strncpy" } */
T ("0123", a, a + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[1, 5] may overlap up to 4 bytes at offset \\\[4, 1]" "strncpy" } */
T ("0123", a, a + i, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and \\\[1, 5] may overlap up to 2 bytes at offset \\\[1, 2]" "strncpy" } */
T ("0123", a, a + i, 4); /* { dg-warning "accessing 4 bytes at offsets 0 and \\\[1, 5] may overlap up to 3 bytes at offset \\\[1, 3]" "strncpy" } */
T ("0123", a, a + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[1, 5] may overlap up to 4 bytes at offset \\\[1, 4]" "strncpy" } */
i = SR (2, 5);
T ("0123", a, a + i, 0);
T ("0123", a, a + i, 1);
T ("0123", a, a + i, 2);
T ("0123", a, a + i, 3); /* { dg-warning "accessing 3 bytes at offsets 0 and \\\[2, 5] may overlap 1 byte at offset 2" "strncpy" } */
T ("0123", a, a + i, 4); /* { dg-warning "accessing 4 bytes at offsets 0 and \\\[2, 5] may overlap up to 2 bytes at offset \\\[3, 2]" "strncpy" } */
T ("0123", a, a + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2, 5] may overlap up to 3 bytes at offset \\\[4, 2]" "strncpy" } */
T ("0123", a, a + i, 6); /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[2, 5] may overlap up to 3 bytes at offset \\\[4, 2]" "strncpy" } */
T ("0123", a, a + i, 4); /* { dg-warning "accessing 4 bytes at offsets 0 and \\\[2, 5] may overlap up to 2 bytes at offset \\\[2, 3]" "strncpy" } */
T ("0123", a, a + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[2, 5] may overlap up to 3 bytes at offset \\\[2, 4]" "strncpy" } */
/* When i == 5 the following overlaps at least 1 byte: the nul at a[5]
(if a + 5 is the empty string). If a + 5 is not empty then it overlaps
it plus as many non-nul characters after it, up to the total of 6. */
T ("0123", a, a + i, 6); /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[2, 5] overlaps between 1 and 3 bytes at offset \\\[2, 5]" "strncpy" } */
i = SR (3, 5);
T ("0123", a, a + i, 0);
......@@ -887,8 +890,14 @@ void test_strncpy_range (char *d, size_t n)
T ("0123", a, a + i, 2);
T ("0123", a, a + i, 3);
T ("0123", a, a + i, 4); /* { dg-warning "accessing 4 bytes at offsets 0 and \\\[3, 5] may overlap 1 byte at offset 3" "strncpy" } */
T ("0123", a, a + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[3, 5] may overlap up to 2 bytes at offset \\\[4, 3]" "strncpy" } */
T ("0123", a, a + i, 6); /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[3, 5] may overlap up to 2 bytes at offset \\\[4, 3]" "strncpy" } */
T ("0123", a, a + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[3, 5] may overlap up to 2 bytes at offset \\\[3, 4]" "strncpy" } */
/* The following copy overlaps at most 2 bytes. When i == 3 it overlaps
the 2 bytes at "3", when i == 4 just the final nul. When i == 5 it
also overlaps 1 byte, the nul at a[5]. Although the overlap offset
range suggests the overlap is up to three bytes, it correctly reflects
the union of the two cases. */
T ("0123", a, a + i, 6); /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[3, 5] overlaps between 1 and 2 bytes at offset \\\[3, 5]" "strncpy" } */
i = SR (4, 5);
T ("0123", a, a + i, 0);
......@@ -897,7 +906,11 @@ void test_strncpy_range (char *d, size_t n)
T ("0123", a, a + i, 3);
T ("0123", a, a + i, 4);
T ("0123", a, a + i, 5); /* { dg-warning "accessing 5 bytes at offsets 0 and \\\[4, 5] may overlap 1 byte at offset 4" "strncpy" } */
T ("0123", a, a + i, 6); /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[4, 5] may overlap 1 byte at offset 4" "strncpy" } */
/* Regardless of the value of i, the following overlaps exactlty
one byte: the nul at a[4]. There is no overlap at a[5] because
the source is not read past the nul so the offset below isn't
entirely correct. */
T ("0123", a, a + i, 6); /* { dg-warning "accessing 6 bytes at offsets 0 and \\\[4, 5] overlaps 1 byte at offset \\\[4, 5]" "strncpy" } */
/* Verify offset and size both in some range. The strncpy checking
is more strict than that of memcpy and triggers even when the
......@@ -911,10 +924,10 @@ void test_strncpy_range (char *d, size_t n)
i = 5: 567* none
567*. none
567*.. overlaps 1 at offset 5 */
T ("01234567", a, a + i, UR (4, 6)); /* { dg-warning "accessing between 4 and 6 bytes at offsets 0 and \\\[4, 5] may overlap up to 2 bytes at offset \\\[5, 4]" "strncpy" } */
T ("01234567", a, a + i, UR (4, 6)); /* { dg-warning "accessing between 4 and 6 bytes at offsets 0 and \\\[4, 5] may overlap up to 2 bytes at offset \\\[4, 5]" "strncpy" } */
/* Ditto for objects of unknown sizes. */
T ("01234567", d, d + i, UR (4, 6)); /* { dg-warning "accessing between 4 and 6 bytes at offsets 0 and \\\[4, 5] may overlap up to 2 bytes at offset \\\[5, 4]" "strncpy" } */
T ("01234567", d, d + i, UR (4, 6)); /* { dg-warning "accessing between 4 and 6 bytes at offsets 0 and \\\[4, 5] may overlap up to 2 bytes at offset \\\[4, 5]" "strncpy" } */
T ("01234567", a, a + i, UR (6, 7)); /* { dg-warning "accessing between 6 and 7 bytes at offsets 0 and \\\[4, 5] overlaps between 1 and 3 bytes at offset \\\[4, 5]" "strncpy" } */
......
/* PR middle-end/94647 - bogus -Warray-bounds on strncpy into a larger
member array from a smaller array
{ dg-do compile }
{ dg-options "-O2 -Wall" } */
typedef __SIZE_TYPE__ size_t;
extern char* strncpy (char*, const char*, size_t);
char a4[4], a8[8];
void nowarn_nonmeber (void)
{
/* The following would deserve a warning if A4 were known not to be
nul-terminated (or declared with attribute nonstring). */
strncpy (a8, a4, sizeof a8);
}
struct S
{
char a4[4], a8[8];
};
void nowarn_member (struct S *p, struct S *q)
{
/* The following would deserve a warning if A4 were known either
not to be nul-terminated (e.g., declared nonstring) or to be
uninitialized. */
strncpy (p->a8, p->a4, sizeof p->a8); // { dg-bogus "\\\[-Warray-bounds" }
}
......@@ -63,7 +63,7 @@ test_arr_strcpy_1 (void)
void __attribute__ ((noclone, noinline))
test_arr_strcpy_2 (void)
{
strcpy (b.a, &b.a[i]);
strcpy (b.a, &b.a[i]); /* { dg-warning "\\\[-Wrestrict" } */
}
......
......@@ -26,7 +26,7 @@ void test_memcpy_nowarn (char *d)
void test_strncpy_warn (char *d)
{
strncpy (d + 1, d + 3, 5); /* { dg-warning "accessing 5 bytes at offsets 1 and 3 overlaps 2 bytes at offset 3" } */
strncpy (d + 1, d + 3, 5); /* { dg-warning "accessing 5 bytes at offsets 1 and 3 overlaps between 1 and 2 bytes at offset 3" } */
}
void test_strncpy_nowarn (char *d)
......
......@@ -21,7 +21,7 @@ void warn_2_smax_p2 (void)
ptrdiff_t i = UR (2, DIFF_MAX + (size_t)2);
strcpy (d, d + i); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
strcpy (d, d + i); /* { dg-warning "accessing between 1 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset \\\[2, 3]" } */
sink (d);
}
......@@ -47,7 +47,7 @@ void warn_2u_smax_p2 (void)
size_t i = UR (2, DIFF_MAX + (size_t)2);
strcpy (d, d + i); /* { dg-warning "accessing between 0 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset 2" } */
strcpy (d, d + i); /* { dg-warning "accessing between 1 and 4 bytes at offsets 0 and \\\[2, 7] may overlap up to 2 bytes at offset \\\[2, 3]" } */
sink (d);
}
......
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