PR middle-end/91679 - missing -Warray-bounds accessing a member array in a local buffer
PR middle-end/91679 - missing -Warray-bounds accessing a member array in a local buffer PR middle-end/91647 - new FAILs for Warray-bounds-8 and Wstringop-overflow-3.C PR middle-end/91463 - missing -Warray-bounds accessing past the end of a statically initialized flexible array member PR middle-end/92312 - bogus -Wstringop-overflow storing into a trailing array backed by larger buffer gcc/ChangeLog: PR middle-end/91679 PR middle-end/91647 PR middle-end/91463 PR middle-end/92312 * c-family/c-pretty-print.c (direct_abstract_declarator): Print bound in zero-length arrays. * gcc/c-family/c.opt (-Wzero-length-bounds): New option. * gcc/doc/invoke.texi (-Wzero-length-bounds): Document. * gimple-match-head.c (try_conditional_simplification): Use memcpy instead of a hand-rolled loop to avoid PR 92323. * tree-vrp.c (vrp_prop::check_array_ref): Handle trailing arrays with initializers. (vrp_prop::check_mem_ref): Handle declared struct objects. * tree.c (last_field): New function. (array_at_struct_end_p): Handle MEM_REF. (get_initializer_for): New helper. (component_ref_size): Add argument. Rename locals. Call get_initializer_for instead of fold_ctor_reference. Correct handling of flexible array members. * wide-int.h (generic_wide_int <storage>::sign_mask): Assert invariant. gcc/testsuite/ChangeLog: PR middle-end/91679 PR middle-end/91647 PR middle-end/91463 PR middle-end/92312 * c-c++-common/Warray-bounds-2.c: Disable VRP. Adjust expected messages. * g++.dg/warn/Warray-bounds-8.C: Remove xfails. * gcc.dg/Warray-bounds-48.c: New test. * gcc.dg/Warray-bounds-49.c: New test. * gcc.dg/Wstringop-overflow-16.c: Adjust text of expected messages. * gcc.dg/Wstringop-overflow-21.c: New test. * gcc.dg/Wzero-length-array-bounds.c: New test. * gcc.dg/pr36902.c: Remove xfail. * gcc.dg/strlenopt-57.c: Add an expected warning. From-SVN: r277728
This commit is contained in:
parent
8dc56a2244
commit
49fb45c81f
@ -1,3 +1,26 @@
|
||||
2019-11-01 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/91679
|
||||
PR middle-end/91647
|
||||
PR middle-end/91463
|
||||
PR middle-end/92312
|
||||
* c-family/c-pretty-print.c (direct_abstract_declarator): Print
|
||||
bound in zero-length arrays.
|
||||
* gcc/c-family/c.opt (-Wzero-length-bounds): New option.
|
||||
* gcc/doc/invoke.texi (-Wzero-length-bounds): Document.
|
||||
* gimple-match-head.c (try_conditional_simplification): Use memcpy
|
||||
instead of a hand-rolled loop to avoid PR 92323.
|
||||
* tree-vrp.c (vrp_prop::check_array_ref): Handle trailing arrays
|
||||
with initializers.
|
||||
(vrp_prop::check_mem_ref): Handle declared struct objects.
|
||||
* tree.c (last_field): New function.
|
||||
(array_at_struct_end_p): Handle MEM_REF.
|
||||
(get_initializer_for): New helper.
|
||||
(component_ref_size): Add argument. Rename locals. Call
|
||||
get_initializer_for instead of fold_ctor_reference. Correct handling
|
||||
of flexible array members.
|
||||
* wide-int.h (generic_wide_int <storage>::sign_mask): Assert invariant.
|
||||
|
||||
2019-11-01 Kewen Lin <linkw@gcc.gnu.org>
|
||||
|
||||
* config/rs6000/rs6000-modes.def (V2SF, V2SI): New modes.
|
||||
|
@ -581,16 +581,20 @@ c_pretty_printer::direct_abstract_declarator (tree t)
|
||||
|
||||
case ARRAY_TYPE:
|
||||
pp_c_left_bracket (this);
|
||||
if (TYPE_DOMAIN (t) && TYPE_MAX_VALUE (TYPE_DOMAIN (t)))
|
||||
if (tree dom = TYPE_DOMAIN (t))
|
||||
{
|
||||
tree maxval = TYPE_MAX_VALUE (TYPE_DOMAIN (t));
|
||||
tree type = TREE_TYPE (maxval);
|
||||
if (tree maxval = TYPE_MAX_VALUE (dom))
|
||||
{
|
||||
tree type = TREE_TYPE (maxval);
|
||||
|
||||
if (tree_fits_shwi_p (maxval))
|
||||
pp_wide_integer (this, tree_to_shwi (maxval) + 1);
|
||||
if (tree_fits_shwi_p (maxval))
|
||||
pp_wide_integer (this, tree_to_shwi (maxval) + 1);
|
||||
else
|
||||
expression (fold_build2 (PLUS_EXPR, type, maxval,
|
||||
build_int_cst (type, 1)));
|
||||
}
|
||||
else
|
||||
expression (fold_build2 (PLUS_EXPR, type, maxval,
|
||||
build_int_cst (type, 1)));
|
||||
pp_string (this, "0");
|
||||
}
|
||||
pp_c_right_bracket (this);
|
||||
direct_abstract_declarator (TREE_TYPE (t));
|
||||
|
@ -338,6 +338,10 @@ Warray-bounds=
|
||||
LangEnabledBy(C ObjC C++ LTO ObjC++,Wall,1,0)
|
||||
; in common.opt
|
||||
|
||||
Wzero-length-bounds
|
||||
C ObjC C++ ObjC++ Var(warn_zero_length_bounds) Warning LangEnabledBy(C ObjC C++ ObjC++,Wall)
|
||||
Warn about accesses to interior zero-length array members.
|
||||
|
||||
Wassign-intercept
|
||||
ObjC ObjC++ Var(warn_assign_intercept) Warning
|
||||
Warn whenever an Objective-C assignment is being intercepted by the garbage collector.
|
||||
|
@ -325,6 +325,7 @@ Objective-C and Objective-C++ Dialects}.
|
||||
-Winaccessible-base @gol
|
||||
-Winit-self -Winline -Wno-int-conversion -Wint-in-bool-context @gol
|
||||
-Wno-int-to-pointer-cast -Winvalid-memory-model -Wno-invalid-offsetof @gol
|
||||
-Wzero-length-bounds @gol
|
||||
-Winvalid-pch -Wlarger-than=@var{byte-size} @gol
|
||||
-Wlogical-op -Wlogical-not-parentheses -Wlong-long @gol
|
||||
-Wmain -Wmaybe-uninitialized -Wmemset-elt-size -Wmemset-transposed-args @gol
|
||||
@ -4438,6 +4439,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect Options}.
|
||||
-Wimplicit-int @r{(C and Objective-C only)} @gol
|
||||
-Wimplicit-function-declaration @r{(C and Objective-C only)} @gol
|
||||
-Winit-self @r{(only for C++)} @gol
|
||||
-Wzero-length-bounds @gol
|
||||
-Wlogical-not-parentheses @gol
|
||||
-Wmain @r{(only for C/ObjC and unless} @option{-ffreestanding}@r{)} @gol
|
||||
-Wmaybe-uninitialized @gol
|
||||
@ -6330,6 +6332,33 @@ conversions. This warning is about implicit conversions; for explicit
|
||||
conversions the warnings @option{-Wno-int-to-pointer-cast} and
|
||||
@option{-Wno-pointer-to-int-cast} may be used.
|
||||
|
||||
@item -Wzero-length-bounds
|
||||
@opindex Wzero-length-bounds
|
||||
@opindex Wzero-length-bounds
|
||||
Warn about accesses to elements of zero-length array members that might
|
||||
overlap other members of the same object. Declaring interior zero-length
|
||||
arrays is discouraged because accesses to them are undefined. See
|
||||
@xref{Zero Length}.
|
||||
|
||||
For example, the first two stores in function @code{bad} are diagnosed
|
||||
because the array elements overlap the subsequent members @code{b} and
|
||||
@code{c}. The third store is diagnosed by @option{-Warray-bounds}
|
||||
because it is beyond the bounds of the enclosing object.
|
||||
|
||||
@smallexample
|
||||
struct X @{ int a[0]; int b, c; @};
|
||||
struct X x;
|
||||
|
||||
void bad (void)
|
||||
@{
|
||||
x.a[0] = 0; // -Wzero-length-bounds
|
||||
x.a[1] = 1; // -Wzero-length-bounds
|
||||
x.a[2] = 2; // -Warray-bounds
|
||||
@}
|
||||
@end smallexample
|
||||
|
||||
Option @option{-Wzero-length-bounds} is enabled by @option{-Warray-bounds}.
|
||||
|
||||
@item -Wno-div-by-zero
|
||||
@opindex Wno-div-by-zero
|
||||
@opindex Wdiv-by-zero
|
||||
|
@ -837,8 +837,8 @@ try_conditional_simplification (internal_fn ifn, gimple_match_op *res_op,
|
||||
gimple_match_op cond_op (gimple_match_cond (res_op->ops[0],
|
||||
res_op->ops[num_ops - 1]),
|
||||
op, res_op->type, num_ops - 2);
|
||||
for (unsigned int i = 1; i < num_ops - 1; ++i)
|
||||
cond_op.ops[i - 1] = res_op->ops[i];
|
||||
|
||||
memcpy (cond_op.ops, res_op->ops + 1, (num_ops - 1) * sizeof *cond_op.ops);
|
||||
switch (num_ops - 2)
|
||||
{
|
||||
case 2:
|
||||
|
@ -1,3 +1,19 @@
|
||||
2019-11-01 Martin Sebor <msebor@redhat.com>
|
||||
|
||||
PR middle-end/91679
|
||||
PR middle-end/91647
|
||||
PR middle-end/91463
|
||||
PR middle-end/92312
|
||||
* c-c++-common/Warray-bounds-2.c: Disable VRP. Adjust expected messages.
|
||||
* g++.dg/warn/Warray-bounds-8.C: Remove xfails.
|
||||
* gcc.dg/Warray-bounds-48.c: New test.
|
||||
* gcc.dg/Warray-bounds-49.c: New test.
|
||||
* gcc.dg/Wstringop-overflow-16.c: Adjust text of expected messages.
|
||||
* gcc.dg/Wstringop-overflow-21.c: New test.
|
||||
* gcc.dg/Wzero-length-array-bounds.c: New test.
|
||||
* gcc.dg/pr36902.c: Remove xfail.
|
||||
* gcc.dg/strlenopt-57.c: Add an expected warning.
|
||||
|
||||
2019-11-01 Steven G. Kargl <kargl@gcc.gnu.org>
|
||||
|
||||
* gfortran.dg/byte_3.f: New test.
|
||||
|
@ -6,7 +6,7 @@
|
||||
source of the excessive array bound is in a different function than
|
||||
the call.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Warray-bounds -Wno-stringop-overflow" } */
|
||||
{ dg-options "-O2 -Warray-bounds -Wno-stringop-overflow -fno-tree-vrp" } */
|
||||
|
||||
#if __has_include (<stddef.h>)
|
||||
# include <stddef.h>
|
||||
@ -216,13 +216,13 @@ void call_strncpy_dst_diff_max (const char *s, size_t n)
|
||||
static void
|
||||
wrap_strncpy_dstarray_diff_neg (char *d, const char *s, ptrdiff_t i, size_t n)
|
||||
{
|
||||
strncpy (d + i, s, n); /* { dg-bogus "offset -\[0-9\]+ is out of the bounds \\\[0, 90] of object .ar10. with type .(struct )?Array ?\\\[2]." "strncpy" } */
|
||||
} /* { dg-warning "array subscript -1 is outside array bounds" "" { target *-*-* } .-1 } */
|
||||
strncpy (d + i, s, n); /* { dg-warning "offset -\[0-9\]+ is out of the bounds \\\[0, 90] of object .ar10. with type .(struct )?Array ?\\\[2]." "strncpy" } */
|
||||
}
|
||||
|
||||
void call_strncpy_dstarray_diff_neg (const char *s, size_t n)
|
||||
{
|
||||
struct Array ar10[2]; /* { dg-bogus ".ar10. declared here" } */
|
||||
sink (&ar10); /* { dg-message "while referencing" "" { target *-*-* } .-1 } */
|
||||
struct Array ar10[2]; /* { dg-message ".ar10. declared here" } */
|
||||
sink (&ar10);
|
||||
|
||||
int off = (char*)ar10[1].a17 - (char*)ar10 + 1;
|
||||
wrap_strncpy_dstarray_diff_neg (ar10[1].a17, s, -off, n);
|
||||
|
@ -13,7 +13,7 @@ void sink (void*);
|
||||
struct Ax
|
||||
{
|
||||
char n;
|
||||
char a[]; // { dg-message "while referencing .Ax::a." "pr91463" { xfail *-*-* } }
|
||||
char a[]; // { dg-message "while referencing .Ax::a." }
|
||||
};
|
||||
|
||||
// Verify warning for a definition with no initializer.
|
||||
@ -21,9 +21,9 @@ Ax ax_;
|
||||
|
||||
void gax_ ()
|
||||
{
|
||||
ax_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
ax_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
ax_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
// Verify warning for access to a definition with an initializer that doesn't
|
||||
@ -32,9 +32,9 @@ Ax ax0 = { 0 };
|
||||
|
||||
void gax0 ()
|
||||
{
|
||||
ax0.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax0.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax0.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax0.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
ax0.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
ax0.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
// Verify warning for access to a definition with an initializer that
|
||||
@ -43,9 +43,9 @@ Ax ax0_ = { 0, { } };
|
||||
|
||||
void gax0_ ()
|
||||
{
|
||||
ax0_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax0_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax0_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax0_.a[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
ax0_.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
ax0_.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
// Verify warning for out-of-bounds accesses to a definition with
|
||||
@ -55,8 +55,8 @@ Ax ax1 = { 1, { 0 } };
|
||||
void gax1 ()
|
||||
{
|
||||
ax1.a[0] = 0;
|
||||
ax1.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax1.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax1.a[1] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
ax1.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
Ax ax2 = { 2, { 1, 0 } };
|
||||
@ -65,7 +65,7 @@ void gax2 ()
|
||||
{
|
||||
ax2.a[0] = 0;
|
||||
ax2.a[1] = 0;
|
||||
ax2.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
ax2.a[2] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
|
||||
@ -308,14 +308,14 @@ void ga1ix ()
|
||||
struct Bx
|
||||
{
|
||||
char n;
|
||||
char a[]; // { dg-message "while referencing .Bx::a." "pr91463" { xfail *-*-* } }
|
||||
char a[]; // { dg-message "while referencing .Bx::a." }
|
||||
|
||||
// Verify the warning for a constant.
|
||||
Bx () { a[0] = 0; } // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
Bx () { a[0] = 0; } // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
||||
// And also for a non-constant. Regardless of the subscript, the array
|
||||
// of the object in function gxi() below has a zero size.
|
||||
Bx (int i) { a[i] = 0; } // { dg-warning "\\\[-Warray-bounds" "pr91463" { xfail *-*-* } }
|
||||
Bx (int i) { a[i] = 0; } // { dg-warning "\\\[-Warray-bounds" }
|
||||
};
|
||||
|
||||
void gbx (void)
|
||||
|
@ -67,7 +67,7 @@ void strcpy_global (void)
|
||||
|
||||
SA (__builtin_offsetof (struct MA17, ax) == 157);
|
||||
|
||||
T (gma.ax, 0); // { dg-warning "'strcpy' offset 157 is out of the bounds \\\[0, 157] of object 'gma' with type 'struct MA17'" }
|
||||
T (gma.ax, 0); // { dg-warning "'strcpy' offset 157 from the object at 'gma' is out of the bounds of referenced subobject 'ax' with type 'char[]' at offset 157|'strcpy' offset 157 is out of the bounds \\\[0, 157] of object 'gma' with type 'struct MA17'" }
|
||||
}
|
||||
|
||||
|
||||
@ -92,16 +92,16 @@ void strcpy_global_array (void)
|
||||
T (gma2[0].a17, 16);
|
||||
T (gma2[0].a17, 17); // { dg-warning "'strcpy' offset 157 from the object at 'gma2' is out of the bounds of referenced subobject 'a17' with type 'char\\\[17]' at offset 140" }
|
||||
|
||||
/* GMA2 is external buts because it's an array its definition in another
|
||||
/* GMA2 is external but because it's an array its definition in another
|
||||
translation unit may not provide an initializer for the flexible array
|
||||
member. Verify that a warning is issued for access to it. */
|
||||
T (gma2[0].ax, 1); // { dg-warning "'strcpy' offset \\\[157, 158] from the object at 'gma2' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" }
|
||||
T (gma2[0].ax, 7); // { dg-warning "'strcpy' offset \\\[157, 164] from the object at 'gma2' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" }
|
||||
T (gma2[0].ax, 1); // { dg-warning "'strcpy' offset \\\[157, 158] from the object at 'gma2' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 157" }
|
||||
T (gma2[0].ax, 7); // { dg-warning "'strcpy' offset \\\[157, 164] from the object at 'gma2' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 157" }
|
||||
|
||||
/* IGMA_ is internal and provides on definition for the flexible array
|
||||
member. Verify that a warnin is issued for out-of-bounds accesses
|
||||
to it. */
|
||||
T (igma2_[0].ax, 1); // { dg-warning "'strcpy' offset \\\[157, 158] from the object at 'igma2_' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" }
|
||||
T (igma2_[0].ax, 1); // { dg-warning "'strcpy' offset \\\[157, 158] from the object at 'igma2_' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 157" }
|
||||
|
||||
T (igma_3.ax, 0);
|
||||
T (igma_3.ax, 1);
|
||||
@ -134,7 +134,7 @@ void strcpy_local (void)
|
||||
T (lma.a17, 16);
|
||||
T (lma.a17, 17); // { dg-warning "'strcpy' offset 157 from the object at 'lma' is out of the bounds of referenced subobject 'a17' with type 'char\\\[17]' at offset 140" }
|
||||
|
||||
T (lma.ax, 0); // { dg-warning "'strcpy' offset 157 from the object at 'lma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 157" }
|
||||
T (lma.ax, 0); // { dg-warning "'strcpy' offset 157 from the object at 'lma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 157" }
|
||||
}
|
||||
|
||||
|
||||
@ -191,11 +191,11 @@ void strcpy_ref (struct MA17 *pma)
|
||||
array. The warning assumes that PMA doesn't point to the last element
|
||||
of the array which could in theory have nonzero elements without
|
||||
overlapping other objects. */
|
||||
T (pma[1].ax, 0); // { dg-warning "'strcpy' offset 314 from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 314" }
|
||||
T ((pma + 1)->ax, 1); // { dg-warning "'strcpy' offset \\\[314, 315] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 314" }
|
||||
T ((pma + 1)[1].ax, 2); // { dg-warning "'strcpy' offset \\\[471, 473] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 471" }
|
||||
T ((*(pma + 2)).ax, 2); // { dg-warning "'strcpy' offset \\\[471, 473] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 471" }
|
||||
T (pma[3].ax, 9); // { dg-warning "'strcpy' offset \\\[628, 637] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[]' at offset 628" }
|
||||
T (pma[1].ax, 0); // { dg-warning "'strcpy' offset 314 from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 314" }
|
||||
T ((pma + 1)->ax, 1); // { dg-warning "'strcpy' offset \\\[314, 315] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 314" }
|
||||
T ((pma + 1)[1].ax, 2); // { dg-warning "'strcpy' offset \\\[471, 473] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 471" }
|
||||
T ((*(pma + 2)).ax, 2); // { dg-warning "'strcpy' offset \\\[471, 473] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 471" }
|
||||
T (pma[3].ax, 9); // { dg-warning "'strcpy' offset \\\[628, 637] from the object at 'pma' is out of the bounds of referenced subobject 'ax' with type 'char\\\[0]' at offset 628" }
|
||||
|
||||
T (pma[-1].a1, 0);
|
||||
T (pma[-1].a1, 1); // { dg-warning "'strcpy' offset -152 from the object at 'pma' is out of the bounds of referenced subobject 'a1' with type 'char\\\[1]' at offset -153" }
|
||||
|
363
gcc/testsuite/gcc.dg/Warray-bounds-48.c
Normal file
363
gcc/testsuite/gcc.dg/Warray-bounds-48.c
Normal file
@ -0,0 +1,363 @@
|
||||
/* PR middle-end/91647 - missing -Warray-bounds accessing a zero-length array
|
||||
of a declared object
|
||||
{ dg-do "compile" }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
typedef __INT16_TYPE__ int16_t;
|
||||
typedef __INT32_TYPE__ int32_t;
|
||||
|
||||
void sink (void*);
|
||||
|
||||
/* Exercise a true flexible member. */
|
||||
|
||||
struct AX
|
||||
{
|
||||
int32_t n;
|
||||
int16_t ax[]; // { dg-message "while referencing 'ax'" "member" }
|
||||
};
|
||||
|
||||
static void warn_ax_local (struct AX *p)
|
||||
{
|
||||
p->ax[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->ax[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void nowarn_ax_extern (struct AX *p)
|
||||
{
|
||||
p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999;
|
||||
}
|
||||
|
||||
static void warn_ax_local_buf (struct AX *p)
|
||||
{
|
||||
p->ax[0] = 4; p->ax[1] = 5;
|
||||
|
||||
p->ax[2] = 6; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->ax[3] = 7; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->ax[4] = 8; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_ax_extern_buf (struct AX *p)
|
||||
{
|
||||
p->ax[0] = 9; p->ax[1] = 10; p->ax[2] = 11;
|
||||
|
||||
p->ax[3] = 12; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->ax[4] = 13; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->ax[5] = 14; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void nowarn_ax_extern_bufx (struct AX *p)
|
||||
{
|
||||
p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999;
|
||||
}
|
||||
|
||||
static void nowarn_ax_ref (struct AX *p)
|
||||
{
|
||||
p->ax[0] = 0; p->ax[99] = 99; p->ax[999] = 999; p->ax[9999] = 9999;
|
||||
}
|
||||
|
||||
void test_ax (struct AX *p, unsigned n)
|
||||
{
|
||||
{
|
||||
struct AX sax; // { dg-message "defined here" "struct definition" }
|
||||
warn_ax_local (&sax);
|
||||
sink (&sax);
|
||||
}
|
||||
|
||||
{
|
||||
extern
|
||||
struct AX xsax;
|
||||
nowarn_ax_extern (&xsax);
|
||||
sink (&xsax);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify out-of-bounds access to the local BUF is diagnosed. */
|
||||
char ax_buf_p2[sizeof (struct AX) + 2 * sizeof (int16_t)];
|
||||
warn_ax_local_buf ((struct AX*) ax_buf_p2);
|
||||
sink (ax_buf_p2);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify out-of-bounds access to the extern BUF with a known
|
||||
bound is diagnosed. */
|
||||
extern char ax_buf_p3[sizeof (struct AX) + 3 * sizeof (int16_t)];
|
||||
warn_ax_extern_buf ((struct AX*) ax_buf_p3);
|
||||
sink (ax_buf_p3);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify that accesses to BUFX with an unknown bound are not
|
||||
diagnosed. */
|
||||
extern char bufx[];
|
||||
nowarn_ax_extern_bufx ((struct AX*) bufx);
|
||||
sink (bufx);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify that accesses to BUFN with a runtime bound are not
|
||||
diagnosed. */
|
||||
char bufn[n];
|
||||
nowarn_ax_extern_bufx ((struct AX*) bufn);
|
||||
sink (bufn);
|
||||
}
|
||||
|
||||
nowarn_ax_ref (p);
|
||||
}
|
||||
|
||||
|
||||
/* Exercise a zero-length trailing member array. It's the same as above
|
||||
except that extern declarations with no definitions are considered to
|
||||
have zero elements (they can't be initialized to have any). */
|
||||
|
||||
struct A0
|
||||
{
|
||||
int32_t n;
|
||||
int16_t a0[0]; // { dg-message "while referencing 'a0'" "member" }
|
||||
};
|
||||
|
||||
static void warn_a0_local (struct A0 *p)
|
||||
{
|
||||
p->a0[0] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a0[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a0_extern (struct A0 *p)
|
||||
{
|
||||
p->a0[0] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a0[1] = 3; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a0_local_buf (struct A0 *p)
|
||||
{
|
||||
p->a0[0] = 4; p->a0[1] = 5;
|
||||
|
||||
p->a0[2] = 6; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a0[3] = 7; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a0[4] = 8; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a0_extern_buf (struct A0 *p)
|
||||
{
|
||||
p->a0[0] = 9; p->a0[1] = 10; p->a0[2] = 11;
|
||||
|
||||
p->a0[3] = 12; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a0[4] = 13; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a0[5] = 14; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void nowarn_a0_extern_bufx (struct A0 *p)
|
||||
{
|
||||
p->a0[0] = 0; p->a0[99] = 99; p->a0[999] = 999; p->a0[9999] = 9999;
|
||||
}
|
||||
|
||||
static void nowarn_a0_ref (struct A0 *p)
|
||||
{
|
||||
p->a0[0] = 0; p->a0[99] = 99; p->a0[999] = 999; p->a0[9999] = 9999;
|
||||
}
|
||||
|
||||
void test_a0 (struct A0 *p, unsigned n)
|
||||
{
|
||||
{
|
||||
struct A0 sa0; // { dg-message "defined here" "struct definition" }
|
||||
warn_a0_local (&sa0);
|
||||
sink (&sa0);
|
||||
}
|
||||
|
||||
{
|
||||
extern
|
||||
struct A0 xsa0; // { dg-message "defined here" "struct definition" }
|
||||
warn_a0_extern (&xsa0);
|
||||
sink (&xsa0);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify out-of-bounds access to the local BUF is diagnosed. */
|
||||
char a0_buf_p2[sizeof (struct A0) + 2 * sizeof (int16_t)];
|
||||
warn_a0_local_buf ((struct A0*) a0_buf_p2);
|
||||
sink (a0_buf_p2);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify out-of-bounds access to the extern BUF with a known
|
||||
bound is diagnosed. */
|
||||
extern char a0_buf_p3[sizeof (struct A0) + 3 * sizeof (int16_t)];
|
||||
warn_a0_extern_buf ((struct A0*) a0_buf_p3);
|
||||
sink (a0_buf_p3);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify that accesses to BUFX with an unknown bound are not
|
||||
diagnosed. */
|
||||
extern char bufx[];
|
||||
nowarn_a0_extern_bufx ((struct A0*) bufx);
|
||||
sink (bufx);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify that accesses to BUFN with a runtime bound are not
|
||||
diagnosed. */
|
||||
char bufn[n];
|
||||
nowarn_a0_extern_bufx ((struct A0*) bufn);
|
||||
sink (bufn);
|
||||
}
|
||||
|
||||
nowarn_a0_ref (p);
|
||||
}
|
||||
|
||||
|
||||
/* Exercise a one-element trailing member array. It's the same as above
|
||||
except that it has exactly one element. */
|
||||
|
||||
struct A1
|
||||
{
|
||||
int32_t n;
|
||||
int16_t a1[1]; // { dg-message "while referencing 'a1'" }
|
||||
};
|
||||
|
||||
static void warn_a1_local_noinit (struct A1 *p)
|
||||
{
|
||||
p->a1[0] = 0;
|
||||
p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a1_extern (struct A1 *p)
|
||||
{
|
||||
p->a1[0] = 0;
|
||||
p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a1_init (struct A1 *p)
|
||||
{
|
||||
p->a1[0] = 0;
|
||||
p->a1[1] = 1; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a1[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a1_local_buf (struct A1 *p)
|
||||
{
|
||||
p->a1[0] = 0; p->a1[1] = 1; p->a1[2] = 2; p->a1[3] = 3;
|
||||
|
||||
p->a1[4] = 4; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a1_extern_buf (struct A1 *p)
|
||||
{
|
||||
p->a1[0] = 0; p->a1[1] = 1; p->a1[2] = 2; p->a1[3] = 3; p->a1[4] = 4;
|
||||
|
||||
p->a1[5] = 5; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void nowarn_a1_extern_bufx (struct A1 *p)
|
||||
{
|
||||
p->a1[0] = 0; p->a1[99] = 99; p->a1[999] = 999; p->a1[9999] = 9999;
|
||||
}
|
||||
|
||||
static void nowarn_a1_ref (struct A1 *p)
|
||||
{
|
||||
p->a1[0] = 0; p->a1[99] = 99; p->a1[999] = 999; p->a1[9999] = 9999;
|
||||
}
|
||||
|
||||
void test_a1 (struct A1 *p, unsigned n)
|
||||
{
|
||||
{
|
||||
struct A1 a1;
|
||||
warn_a1_local_noinit (&a1);
|
||||
sink (&a1);
|
||||
}
|
||||
|
||||
{
|
||||
extern struct A1 a1x;
|
||||
warn_a1_extern (&a1x);
|
||||
sink (&a1x);
|
||||
}
|
||||
{
|
||||
struct A1 a1 = { 0, { 1 } };
|
||||
warn_a1_init (&a1);
|
||||
sink (&a1);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify out-of-bounds access to the local BUF is diagnosed. */
|
||||
char buf_p2[sizeof (struct A1) + 2 * sizeof (int16_t)];
|
||||
warn_a1_local_buf ((struct A1*) buf_p2);
|
||||
sink (buf_p2);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify out-of-bounds access to the extern BUF with a known
|
||||
bound is diagnosed. */
|
||||
extern char a1_buf_p3[sizeof (struct A1) + 3 * sizeof (int16_t)];
|
||||
warn_a1_extern_buf ((struct A1*) a1_buf_p3);
|
||||
sink (a1_buf_p3);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify that accesses to BUFX with an unknown bound are not
|
||||
diagnosed. */
|
||||
extern char bufx[];
|
||||
nowarn_a1_extern_bufx ((struct A1*) bufx);
|
||||
sink (bufx);
|
||||
}
|
||||
|
||||
{
|
||||
/* Verify that accesses to BUFN with a runtime bound are not
|
||||
diagnosed. */
|
||||
char bufn[n];
|
||||
nowarn_a1_extern_bufx ((struct A1*) bufn);
|
||||
sink (bufn);
|
||||
}
|
||||
|
||||
nowarn_a1_ref (p);
|
||||
}
|
||||
|
||||
|
||||
/* Exercise a two-element trailing member array. It's treated
|
||||
the same as an interior array member. */
|
||||
|
||||
struct A2
|
||||
{
|
||||
int32_t n;
|
||||
int16_t a2[2]; // { dg-message "while referencing 'a2'" }
|
||||
};
|
||||
|
||||
static void warn_a2_noinit (struct A2 *p)
|
||||
{
|
||||
p->a2[0] = 0; p->a2[1] = 1;
|
||||
|
||||
p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a2_init (struct A2 *p)
|
||||
{
|
||||
p->a2[0] = 0; p->a2[1] = 1;
|
||||
|
||||
p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a2[9] = 9; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
static void warn_a2_ref (struct A2 *p)
|
||||
{
|
||||
p->a2[0] = 0; p->a2[1] = 1;
|
||||
|
||||
p->a2[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
p->a2[9] = 9; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
||||
|
||||
void test_a2 (struct A2 *p)
|
||||
{
|
||||
{
|
||||
struct A2 a2;
|
||||
warn_a2_noinit (&a2);
|
||||
sink (&a2);
|
||||
}
|
||||
|
||||
{
|
||||
struct A2 a2 = { 0, { 1, 2 } };
|
||||
warn_a2_init (&a2);
|
||||
sink (&a2);
|
||||
}
|
||||
|
||||
warn_a2_ref (p);
|
||||
}
|
115
gcc/testsuite/gcc.dg/Warray-bounds-49.c
Normal file
115
gcc/testsuite/gcc.dg/Warray-bounds-49.c
Normal file
@ -0,0 +1,115 @@
|
||||
/* PR middle-end/91647 - missing -Warray-bounds accessing a zero-length array
|
||||
of a declared object
|
||||
{ dg-do "compile" }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
struct __attribute__ ((aligned (16))) A16
|
||||
{
|
||||
__INT64_TYPE__ i8;
|
||||
__INT16_TYPE__ i2;
|
||||
__INT16_TYPE__ a2[];
|
||||
};
|
||||
|
||||
struct A16 a0 = { };
|
||||
|
||||
void test_a0 (void)
|
||||
{
|
||||
// The first three elements fit in the tail padding.
|
||||
a0.a2[0] = 0; a0.a2[1] = 1; a0.a2[2] = 2;
|
||||
|
||||
a0.a2[3] = 3; // { dg-warning "array subscript 3 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a1 = { .a2 = { 1 } };
|
||||
|
||||
void test_a1 (void)
|
||||
{
|
||||
a1.a2[0] = 0; a1.a2[1] = 1; a1.a2[2] = 2;
|
||||
|
||||
a1.a2[3] = 3; // { dg-warning "array subscript 3 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a2 = { .a2 = { 1, 2 } };
|
||||
|
||||
void test_a2 (void)
|
||||
{
|
||||
a2.a2[0] = 0; a2.a2[1] = 1; a2.a2[2] = 2;
|
||||
|
||||
a2.a2[3] = 3; // { dg-warning "array subscript 3 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a3 = { .a2 = { 1, 2, 3 } };
|
||||
|
||||
void test_a3 (void)
|
||||
{
|
||||
a3.a2[0] = 0; a3.a2[1] = 1; a3.a2[2] = 2;
|
||||
|
||||
a3.a2[3] = 3; // { dg-warning "array subscript 3 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a4 = { .a2 = { 1, 2, 3, 4 } };
|
||||
|
||||
void test_a4 (void)
|
||||
{
|
||||
a4.a2[0] = 0; a4.a2[1] = 1; a4.a2[2] = 2; a4.a2[3] = 3;
|
||||
|
||||
a4.a2[4] = 4; // { dg-warning "array subscript 4 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a5 = { .a2 = { 1, 2, 3, 4, 5 } };
|
||||
|
||||
void test_a5 (void)
|
||||
{
|
||||
a5.a2[0] = 0; a5.a2[1] = 1; a5.a2[2] = 2; a5.a2[3] = 3; a5.a2[4] = 4;
|
||||
|
||||
a5.a2[5] = 5; // { dg-warning "array subscript 5 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a6 = { .a2 = { 1, 2, 3, 4, 5, 6 } };
|
||||
|
||||
void test_a6 (void)
|
||||
{
|
||||
a6.a2[0] = 0; a6.a2[1] = 1; a6.a2[2] = 2; a6.a2[3] = 3; a6.a2[4] = 4;
|
||||
a6.a2[5] = 5;
|
||||
|
||||
a6.a2[6] = 6; // { dg-warning "array subscript 6 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a7 = { .a2 = { 1, 2, 3, 4, 5, 6, 7 } };
|
||||
|
||||
void test_a7 (void)
|
||||
{
|
||||
a7.a2[0] = 0; a7.a2[1] = 1; a7.a2[2] = 2; a7.a2[3] = 3; a7.a2[4] = 4;
|
||||
a7.a2[5] = 5; a7.a2[5] = 5; a7.a2[6] = 6;
|
||||
|
||||
a7.a2[7] = 7; // { dg-warning "array subscript 7 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a8 = { .a2 = { 1, 2, 3, 4, 5, 6, 7, 8 } };
|
||||
|
||||
void test_a8 (void)
|
||||
{
|
||||
a8.a2[0] = 0; a8.a2[1] = 1; a8.a2[2] = 2; a8.a2[3] = 3; a8.a2[4] = 4;
|
||||
a8.a2[5] = 5; a8.a2[5] = 5; a8.a2[6] = 6; a8.a2[7] = 7;
|
||||
|
||||
a8.a2[8] = 8; // { dg-warning "array subscript 8 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
||||
|
||||
|
||||
struct A16 a9 = { .a2 = { 1, 2, 3, 4, 5, 6, 7, 8, 9 } };
|
||||
|
||||
void test_a9 (void)
|
||||
{
|
||||
a8.a2[0] = 8; a8.a2[1] = 7; a8.a2[2] = 6; a8.a2[3] = 5; a8.a2[4] = 4;
|
||||
a8.a2[5] = 3; a8.a2[5] = 2; a8.a2[6] = 1; a8.a2[7] = 0;
|
||||
|
||||
a8.a2[9] = 8; // { dg-warning "array subscript 9 is above array bounds of 'short int\\\[0]'" }
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
struct charseq {
|
||||
unsigned char bytes[0]; // { dg-message "object declared here" }
|
||||
unsigned char bytes[0]; // { dg-message "while referencing|object declared here" }
|
||||
};
|
||||
|
||||
struct locale_ctype_t {
|
||||
@ -15,7 +15,7 @@ void ctype_finish (struct locale_ctype_t *ctype)
|
||||
long unsigned int cnt;
|
||||
for (cnt = 0; cnt < 20; ++cnt) {
|
||||
static struct charseq replace[2];
|
||||
replace[0].bytes[1] = '\0'; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
replace[0].bytes[1] = '\0'; // { dg-warning "\\\[-Warray-bounds|-Wstringop-overflow" }
|
||||
ctype->mboutdigits[cnt] = &replace[0];
|
||||
}
|
||||
}
|
||||
|
59
gcc/testsuite/gcc.dg/Wstringop-overflow-21.c
Normal file
59
gcc/testsuite/gcc.dg/Wstringop-overflow-21.c
Normal file
@ -0,0 +1,59 @@
|
||||
/* PR middle-end/92312 - bogus -Wstringop-overflow storing into a trailing
|
||||
array backed by larger buffer
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall -Wno-array-bounds" } */
|
||||
|
||||
struct S0 { char a, b[0]; };
|
||||
|
||||
void sink (void*);
|
||||
|
||||
void test_memset_zero_length (void)
|
||||
{
|
||||
char a[3];
|
||||
struct S0 *p = (struct S0*)a;
|
||||
p->a = 0;
|
||||
__builtin_memset (p->b, 0, 2);
|
||||
sink (p);
|
||||
|
||||
__builtin_memset (p->b, 0, 3); // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void test_store_zero_length (int i)
|
||||
{
|
||||
char a[3];
|
||||
struct S0 *p = (struct S0*)a;
|
||||
p->a = 0;
|
||||
p->b[0] = 0;
|
||||
p->b[1] = 1; // { dg-bogus "\\\[-Wstringop-overflow" }
|
||||
p->b[2] = 2; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
p->b[i] = 2;
|
||||
sink (p);
|
||||
}
|
||||
|
||||
|
||||
struct Sx { char a, b[]; };
|
||||
|
||||
void test_memset_flexarray (int i)
|
||||
{
|
||||
char a[3];
|
||||
struct Sx *p = (struct Sx*)a;
|
||||
p->a = 0;
|
||||
__builtin_memset (p->b, 0, 2);
|
||||
sink (p);
|
||||
|
||||
__builtin_memset (p->b, 0, 3); // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
sink (p);
|
||||
}
|
||||
|
||||
void test_store_flexarray (int i)
|
||||
{
|
||||
char a[3];
|
||||
struct Sx *p = (struct Sx*)a;
|
||||
p->a = 0;
|
||||
p->b[0] = 0;
|
||||
p->b[1] = 1; // { dg-bogus "\\\[-Wstringop-overflow" }
|
||||
p->b[2] = 1; // { dg-warning "\\\[-Wstringop-overflow" }
|
||||
p->b[i] = 2;
|
||||
sink (p);
|
||||
}
|
88
gcc/testsuite/gcc.dg/Wzero-length-array-bounds.c
Normal file
88
gcc/testsuite/gcc.dg/Wzero-length-array-bounds.c
Normal file
@ -0,0 +1,88 @@
|
||||
/* PR middle-end/91647 - missing -Warray-bounds accessing a zero-length array
|
||||
of a declared object
|
||||
Test to exercise -Wzero-length-bounds.
|
||||
{ dg-do compile }
|
||||
{ dg-options "-O2 -Wall" } */
|
||||
|
||||
void sink (void*);
|
||||
|
||||
struct X { int a[0]; int b, c; };
|
||||
|
||||
extern struct X x;
|
||||
|
||||
void bad (int i, int j)
|
||||
{
|
||||
x.a[0] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
x.a[1] = 1; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
x.a[2] = 2; // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
||||
x.a[i] = 3; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
x.a[j] = 4; // { dg-warning "array subscript 'j' is outside the bounds of an interior zero-length array" }
|
||||
}
|
||||
|
||||
void access_by_reference (struct X *p, int i)
|
||||
{
|
||||
p->a[0] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
p->a[1] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
p->a[2] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
p->a[i] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
}
|
||||
|
||||
|
||||
extern struct X a[2];
|
||||
|
||||
void access_to_array (int i)
|
||||
{
|
||||
a[0].a[0] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
a[0].a[1] = 1; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
/* Accesses to a subsequent element of the enclosing array seem like
|
||||
a more sever problem than those to the next member of the same
|
||||
struct and so might perhaps be better diagnosed by -Warray-bounds.
|
||||
Then again, code that does this sort of crap might as well get what
|
||||
it deserves if it disables -Wzero-length-bounds. */
|
||||
a[0].a[2] = 2; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
|
||||
a[0].a[i] = 3; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
sink (a);
|
||||
|
||||
a[1].a[0] = 4; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
a[1].a[1] = 5; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
a[1].a[2] = 6; // { dg-warning "\\\[-Warray-bounds" }
|
||||
|
||||
a[1].a[i] = 7; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
sink (a);
|
||||
|
||||
a[i].a[0] = 8; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
a[i].a[1] = 9; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
a[i].a[2] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
}
|
||||
|
||||
|
||||
struct Y
|
||||
{
|
||||
struct X a[2], b;
|
||||
int c;
|
||||
};
|
||||
|
||||
extern struct Y y;
|
||||
|
||||
void access_to_member (int i)
|
||||
{
|
||||
y.a[0].a[0] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
y.a[0].a[1] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
y.a[0].a[2] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
sink (a);
|
||||
|
||||
y.a[1].a[0] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
y.a[1].a[1] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
/* Similar to the array case above, accesses to a subsequent member
|
||||
of the "parent" struct seem like a more severe problem than those
|
||||
to the next member of the same struct. */
|
||||
y.a[1].a[2] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
sink (a);
|
||||
|
||||
y.b.a[0] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
y.b.a[1] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
y.b.a[2] = 0; // { dg-warning "\\\[-Wzero-length-bounds" }
|
||||
y.b.a[3] = 0; // { dg-warning "\\\[-Warray-bounds" }
|
||||
}
|
@ -44,7 +44,7 @@ foo2(unsigned char * to, const unsigned char * from, int n)
|
||||
*to = *from;
|
||||
break;
|
||||
case 5:
|
||||
to[4] = from [4]; /* { dg-warning "array subscript is above array bounds" "" { xfail *-*-* } } */
|
||||
to[4] = from [4]; /* { dg-warning "\\\[-Warray-bounds } */
|
||||
break;
|
||||
}
|
||||
return to;
|
||||
|
@ -21,7 +21,7 @@ void test_var_flexarray_cst_off (void)
|
||||
{
|
||||
/* Use arbitrary constants greater than 16 in case GCC ever starts
|
||||
unrolling strlen() calls with small array arguments. */
|
||||
a[0] = 17 < strlen (a0.a + 1);
|
||||
a[0] = 17 < strlen (a0.a + 1); // { dg-warning "\\\[-Warray-bounds" }
|
||||
a[1] = 19 < strlen (a1.a + 1);
|
||||
a[2] = 23 < strlen (a9.a + 9);
|
||||
a[3] = 29 < strlen (ax.a + 3);
|
||||
|
118
gcc/tree-vrp.c
118
gcc/tree-vrp.c
@ -4122,7 +4122,6 @@ bool
|
||||
vrp_prop::check_array_ref (location_t location, tree ref,
|
||||
bool ignore_off_by_one)
|
||||
{
|
||||
const value_range *vr = NULL;
|
||||
tree low_sub, up_sub;
|
||||
tree low_bound, up_bound, up_bound_p1;
|
||||
|
||||
@ -4132,6 +4131,9 @@ vrp_prop::check_array_ref (location_t location, tree ref,
|
||||
low_sub = up_sub = TREE_OPERAND (ref, 1);
|
||||
up_bound = array_ref_up_bound (ref);
|
||||
|
||||
/* Set for accesses to interior zero-length arrays. */
|
||||
bool interior_zero_len = false;
|
||||
|
||||
if (!up_bound
|
||||
|| TREE_CODE (up_bound) != INTEGER_CST
|
||||
|| (warn_array_bounds < 2
|
||||
@ -4152,11 +4154,22 @@ vrp_prop::check_array_ref (location_t location, tree ref,
|
||||
}
|
||||
else
|
||||
{
|
||||
tree maxbound = TYPE_MAX_VALUE (ptrdiff_type_node);
|
||||
tree ptrdiff_max = TYPE_MAX_VALUE (ptrdiff_type_node);
|
||||
tree maxbound = ptrdiff_max;
|
||||
tree arg = TREE_OPERAND (ref, 0);
|
||||
poly_int64 off;
|
||||
|
||||
if (get_addr_base_and_unit_offset (arg, &off) && known_gt (off, 0))
|
||||
if (TREE_CODE (arg) == COMPONENT_REF)
|
||||
{
|
||||
/* Try to determine the size of the trailing array from
|
||||
its initializer (if it has one). */
|
||||
if (tree refsize = component_ref_size (arg, &interior_zero_len))
|
||||
maxbound = refsize;
|
||||
}
|
||||
|
||||
if (maxbound == ptrdiff_max
|
||||
&& get_addr_base_and_unit_offset (arg, &off)
|
||||
&& known_gt (off, 0))
|
||||
maxbound = wide_int_to_tree (sizetype,
|
||||
wi::sub (wi::to_wide (maxbound),
|
||||
off));
|
||||
@ -4185,6 +4198,7 @@ vrp_prop::check_array_ref (location_t location, tree ref,
|
||||
"array subscript %E is above array bounds of %qT",
|
||||
low_bound, artype);
|
||||
|
||||
const value_range *vr = NULL;
|
||||
if (TREE_CODE (low_sub) == SSA_NAME)
|
||||
{
|
||||
vr = get_value_range (low_sub);
|
||||
@ -4195,7 +4209,9 @@ vrp_prop::check_array_ref (location_t location, tree ref,
|
||||
}
|
||||
}
|
||||
|
||||
if (vr && vr->kind () == VR_ANTI_RANGE)
|
||||
if (warned)
|
||||
; /* Do nothing. */
|
||||
else if (vr && vr->kind () == VR_ANTI_RANGE)
|
||||
{
|
||||
if (up_bound
|
||||
&& TREE_CODE (up_sub) == INTEGER_CST
|
||||
@ -4214,39 +4230,51 @@ vrp_prop::check_array_ref (location_t location, tree ref,
|
||||
&& (ignore_off_by_one
|
||||
? !tree_int_cst_le (up_sub, up_bound_p1)
|
||||
: !tree_int_cst_le (up_sub, up_bound)))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Array bound warning for ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
warned = warning_at (location, OPT_Warray_bounds,
|
||||
"array subscript %E is above array bounds of %qT",
|
||||
up_sub, artype);
|
||||
}
|
||||
warned = warning_at (location, OPT_Warray_bounds,
|
||||
"array subscript %E is above array bounds of %qT",
|
||||
up_sub, artype);
|
||||
else if (TREE_CODE (low_sub) == INTEGER_CST
|
||||
&& tree_int_cst_lt (low_sub, low_bound))
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Array bound warning for ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
warned = warning_at (location, OPT_Warray_bounds,
|
||||
"array subscript %E is below array bounds of %qT",
|
||||
low_sub, artype);
|
||||
}
|
||||
warned = warning_at (location, OPT_Warray_bounds,
|
||||
"array subscript %E is below array bounds of %qT",
|
||||
low_sub, artype);
|
||||
|
||||
if (!warned && interior_zero_len)
|
||||
warned = warning_at (location, OPT_Wzero_length_bounds,
|
||||
(TREE_CODE (low_sub) == INTEGER_CST
|
||||
? G_("array subscript %E is outside the bounds "
|
||||
"of an interior zero-length array %qT")
|
||||
: G_("array subscript %qE is outside the bounds "
|
||||
"of an interior zero-length array %qT")),
|
||||
low_sub, artype);
|
||||
|
||||
if (warned)
|
||||
{
|
||||
if (dump_file && (dump_flags & TDF_DETAILS))
|
||||
{
|
||||
fprintf (dump_file, "Array bound warning for ");
|
||||
dump_generic_expr (MSG_NOTE, TDF_SLIM, ref);
|
||||
fprintf (dump_file, "\n");
|
||||
}
|
||||
|
||||
ref = TREE_OPERAND (ref, 0);
|
||||
|
||||
tree rec = NULL_TREE;
|
||||
if (TREE_CODE (ref) == COMPONENT_REF)
|
||||
ref = TREE_OPERAND (ref, 1);
|
||||
{
|
||||
/* For a reference to a member of a struct object also mention
|
||||
the object if it's known. It may be defined in a different
|
||||
function than the out-of-bounds access. */
|
||||
rec = TREE_OPERAND (ref, 0);
|
||||
if (!VAR_P (rec))
|
||||
rec = NULL_TREE;
|
||||
ref = TREE_OPERAND (ref, 1);
|
||||
}
|
||||
|
||||
if (DECL_P (ref))
|
||||
inform (DECL_SOURCE_LOCATION (ref), "while referencing %qD", ref);
|
||||
if (rec && DECL_P (rec))
|
||||
inform (DECL_SOURCE_LOCATION (rec), "defined here %qD", rec);
|
||||
|
||||
TREE_NO_WARNING (ref) = 1;
|
||||
}
|
||||
@ -4391,16 +4419,21 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
|
||||
/* The type of the object being referred to. It can be an array,
|
||||
string literal, or a non-array type when the MEM_REF represents
|
||||
a reference/subscript via a pointer to an object that is not
|
||||
an element of an array. References to members of structs and
|
||||
unions are excluded because MEM_REF doesn't make it possible
|
||||
to identify the member where the reference originated.
|
||||
Incomplete types are excluded as well because their size is
|
||||
not known. */
|
||||
an element of an array. Incomplete types are excluded as well
|
||||
because their size is not known. */
|
||||
tree reftype = TREE_TYPE (arg);
|
||||
if (POINTER_TYPE_P (reftype)
|
||||
|| !COMPLETE_TYPE_P (reftype)
|
||||
|| TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST
|
||||
|| RECORD_OR_UNION_TYPE_P (reftype))
|
||||
|| TREE_CODE (TYPE_SIZE_UNIT (reftype)) != INTEGER_CST)
|
||||
return false;
|
||||
|
||||
/* Except in declared objects, references to trailing array members
|
||||
of structs and union objects are excluded because MEM_REF doesn't
|
||||
make it possible to identify the member where the reference
|
||||
originated. */
|
||||
if (RECORD_OR_UNION_TYPE_P (reftype)
|
||||
&& (!VAR_P (arg)
|
||||
|| (DECL_EXTERNAL (arg) && array_at_struct_end_p (ref))))
|
||||
return false;
|
||||
|
||||
arrbounds[0] = 0;
|
||||
@ -4412,7 +4445,14 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
|
||||
if (tree dom = TYPE_DOMAIN (reftype))
|
||||
{
|
||||
tree bnds[] = { TYPE_MIN_VALUE (dom), TYPE_MAX_VALUE (dom) };
|
||||
if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1])
|
||||
if (TREE_CODE (arg) == COMPONENT_REF)
|
||||
{
|
||||
offset_int size = maxobjsize;
|
||||
if (tree fldsize = component_ref_size (arg))
|
||||
size = wi::to_offset (fldsize);
|
||||
arrbounds[1] = wi::lrshift (size, wi::floor_log2 (eltsize));
|
||||
}
|
||||
else if (array_at_struct_end_p (arg) || !bnds[0] || !bnds[1])
|
||||
arrbounds[1] = wi::lrshift (maxobjsize, wi::floor_log2 (eltsize));
|
||||
else
|
||||
arrbounds[1] = (wi::to_offset (bnds[1]) - wi::to_offset (bnds[0])
|
||||
@ -4434,7 +4474,13 @@ vrp_prop::check_mem_ref (location_t location, tree ref,
|
||||
else
|
||||
{
|
||||
eltsize = 1;
|
||||
arrbounds[1] = wi::to_offset (TYPE_SIZE_UNIT (reftype));
|
||||
tree size = TYPE_SIZE_UNIT (reftype);
|
||||
if (VAR_P (arg))
|
||||
if (tree initsize = DECL_SIZE_UNIT (arg))
|
||||
if (tree_int_cst_lt (size, initsize))
|
||||
size = initsize;
|
||||
|
||||
arrbounds[1] = wi::to_offset (size);
|
||||
}
|
||||
|
||||
offrange[0] += ioff;
|
||||
|
225
gcc/tree.c
225
gcc/tree.c
@ -3089,6 +3089,25 @@ first_field (const_tree type)
|
||||
return t;
|
||||
}
|
||||
|
||||
/* Returns the last FIELD_DECL in the TYPE_FIELDS of the RECORD_TYPE or
|
||||
UNION_TYPE TYPE, or NULL_TREE if none. */
|
||||
|
||||
tree
|
||||
last_field (const_tree type)
|
||||
{
|
||||
tree last = NULL_TREE;
|
||||
|
||||
for (tree fld = TYPE_FIELDS (type); fld; fld = TREE_CHAIN (fld))
|
||||
{
|
||||
if (TREE_CODE (fld) != FIELD_DECL)
|
||||
continue;
|
||||
|
||||
last = fld;
|
||||
}
|
||||
|
||||
return last;
|
||||
}
|
||||
|
||||
/* Concatenate two chains of nodes (chained through TREE_CHAIN)
|
||||
by modifying the last node in chain 1 to point to chain 2.
|
||||
This is the Lisp primitive `nconc'. */
|
||||
@ -13363,8 +13382,8 @@ array_ref_up_bound (tree exp)
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Returns true if REF is an array reference or a component reference
|
||||
to an array at the end of a structure.
|
||||
/* Returns true if REF is an array reference, component reference,
|
||||
or memory reference to an array at the end of a structure.
|
||||
If this is the case, the array may be allocated larger
|
||||
than its upper bound implies. */
|
||||
|
||||
@ -13382,6 +13401,28 @@ array_at_struct_end_p (tree ref)
|
||||
else if (TREE_CODE (ref) == COMPONENT_REF
|
||||
&& TREE_CODE (TREE_TYPE (TREE_OPERAND (ref, 1))) == ARRAY_TYPE)
|
||||
atype = TREE_TYPE (TREE_OPERAND (ref, 1));
|
||||
else if (TREE_CODE (ref) == MEM_REF)
|
||||
{
|
||||
tree arg = TREE_OPERAND (ref, 0);
|
||||
if (TREE_CODE (arg) == ADDR_EXPR)
|
||||
arg = TREE_OPERAND (arg, 0);
|
||||
tree argtype = TREE_TYPE (arg);
|
||||
if (TREE_CODE (argtype) == RECORD_TYPE)
|
||||
{
|
||||
if (tree fld = last_field (argtype))
|
||||
{
|
||||
atype = TREE_TYPE (fld);
|
||||
if (TREE_CODE (atype) != ARRAY_TYPE)
|
||||
return false;
|
||||
if (VAR_P (arg) && DECL_SIZE (fld))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
@ -13498,33 +13539,72 @@ component_ref_field_offset (tree exp)
|
||||
return SUBSTITUTE_PLACEHOLDER_IN_EXPR (DECL_FIELD_OFFSET (field), exp);
|
||||
}
|
||||
|
||||
/* Given the initializer INIT, return the initializer for the field
|
||||
DECL if it exists, otherwise null. Used to obtain the initializer
|
||||
for a flexible array member and determine its size. */
|
||||
|
||||
static tree
|
||||
get_initializer_for (tree init, tree decl)
|
||||
{
|
||||
STRIP_NOPS (init);
|
||||
|
||||
tree fld, fld_init;
|
||||
unsigned HOST_WIDE_INT i;
|
||||
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), i, fld, fld_init)
|
||||
{
|
||||
if (decl == fld)
|
||||
return fld_init;
|
||||
|
||||
if (TREE_CODE (fld) == CONSTRUCTOR)
|
||||
{
|
||||
fld_init = get_initializer_for (fld_init, decl);
|
||||
if (fld_init)
|
||||
return fld_init;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Determines the size of the member referenced by the COMPONENT_REF
|
||||
REF, using its initializer expression if necessary in order to
|
||||
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
|
||||
cannot be determined. */
|
||||
|
||||
tree
|
||||
component_ref_size (tree ref)
|
||||
component_ref_size (tree ref, bool *interior_zero_length /* = NULL */)
|
||||
{
|
||||
gcc_assert (TREE_CODE (ref) == COMPONENT_REF);
|
||||
|
||||
bool int_0_len = false;
|
||||
if (!interior_zero_length)
|
||||
interior_zero_length = &int_0_len;
|
||||
|
||||
tree member = TREE_OPERAND (ref, 1);
|
||||
|
||||
/* If the member is not an array, or is not last, or is an array with
|
||||
more than one element, return its size. Otherwise it's either
|
||||
a bona fide flexible array member, or a zero-length array member,
|
||||
or an array of length one treated as such. */
|
||||
tree size = DECL_SIZE_UNIT (member);
|
||||
if (size)
|
||||
tree memsize = DECL_SIZE_UNIT (member);
|
||||
if (memsize)
|
||||
{
|
||||
tree memtype = TREE_TYPE (member);
|
||||
if (TREE_CODE (memtype) != ARRAY_TYPE
|
||||
|| !array_at_struct_end_p (ref))
|
||||
return size;
|
||||
if (TREE_CODE (memtype) != ARRAY_TYPE)
|
||||
return memsize;
|
||||
|
||||
if (!integer_zerop (size))
|
||||
bool trailing = array_at_struct_end_p (ref);
|
||||
bool zero_length = integer_zerop (memsize);
|
||||
if (!trailing && (!interior_zero_length || !zero_length))
|
||||
/* MEMBER is either an interior array or is an array with
|
||||
more than one element. */
|
||||
return memsize;
|
||||
|
||||
*interior_zero_length = zero_length && !trailing;
|
||||
if (*interior_zero_length)
|
||||
memsize = NULL_TREE;
|
||||
|
||||
if (!zero_length)
|
||||
if (tree dom = TYPE_DOMAIN (memtype))
|
||||
if (tree min = TYPE_MIN_VALUE (dom))
|
||||
if (tree max = TYPE_MAX_VALUE (dom))
|
||||
@ -13533,37 +13613,120 @@ component_ref_size (tree ref)
|
||||
{
|
||||
offset_int minidx = wi::to_offset (min);
|
||||
offset_int maxidx = wi::to_offset (max);
|
||||
if (maxidx - minidx > 1)
|
||||
return size;
|
||||
if (maxidx - minidx > 0)
|
||||
/* MEMBER is an array with more than 1 element. */
|
||||
return memsize;
|
||||
}
|
||||
}
|
||||
|
||||
/* MEMBER is either a bona fide flexible array member, or a zero-length
|
||||
array member, or an array of length one treated as such. */
|
||||
|
||||
/* If the reference is to a declared object and the member a true
|
||||
flexible array, try to determine its size from its initializer. */
|
||||
poly_int64 off = 0;
|
||||
tree base = get_addr_base_and_unit_offset (ref, &off);
|
||||
poly_int64 baseoff = 0;
|
||||
tree base = get_addr_base_and_unit_offset (ref, &baseoff);
|
||||
if (!base || !VAR_P (base))
|
||||
return NULL_TREE;
|
||||
{
|
||||
if (!*interior_zero_length)
|
||||
return NULL_TREE;
|
||||
|
||||
/* The size of any member of a declared object other than a flexible
|
||||
array member is that obtained above. */
|
||||
if (size)
|
||||
return size;
|
||||
if (TREE_CODE (TREE_OPERAND (ref, 0)) != COMPONENT_REF)
|
||||
return NULL_TREE;
|
||||
|
||||
if (tree init = DECL_INITIAL (base))
|
||||
if (TREE_CODE (init) == CONSTRUCTOR)
|
||||
{
|
||||
off <<= LOG2_BITS_PER_UNIT;
|
||||
init = fold_ctor_reference (NULL_TREE, init, off, 0, base);
|
||||
if (init)
|
||||
return TYPE_SIZE_UNIT (TREE_TYPE (init));
|
||||
}
|
||||
base = TREE_OPERAND (ref, 0);
|
||||
baseoff = tree_to_poly_int64 (byte_position (TREE_OPERAND (ref, 1)));
|
||||
}
|
||||
|
||||
/* BASE is the declared object of which MEMBER is either a member
|
||||
or that is is cast to REFTYPE (e.g., a char buffer used to store
|
||||
a REFTYPE object). */
|
||||
tree reftype = TREE_TYPE (TREE_OPERAND (ref, 0));
|
||||
tree basetype = TREE_TYPE (base);
|
||||
|
||||
/* Determine the base type of the referenced object. If it's
|
||||
the same as REFTYPE and MEMBER has a known size, return it. */
|
||||
tree bt = basetype;
|
||||
if (!*interior_zero_length)
|
||||
while (TREE_CODE (bt) == ARRAY_TYPE)
|
||||
bt = TREE_TYPE (bt);
|
||||
bool typematch = useless_type_conversion_p (reftype, bt);
|
||||
if (memsize && typematch)
|
||||
return memsize;
|
||||
|
||||
memsize = NULL_TREE;
|
||||
|
||||
/* MEMBER is a true flexible array member. Compute its size from
|
||||
the initializer of the BASE object if it has one. */
|
||||
if (tree init = DECL_P (base) ? DECL_INITIAL (base) : NULL_TREE)
|
||||
{
|
||||
init = get_initializer_for (init, member);
|
||||
if (init)
|
||||
{
|
||||
memsize = TYPE_SIZE_UNIT (TREE_TYPE (init));
|
||||
if (tree refsize = TYPE_SIZE_UNIT (reftype))
|
||||
{
|
||||
/* Use the larger of the initializer size and the tail
|
||||
padding in the enclosing struct. */
|
||||
poly_int64 rsz = tree_to_poly_int64 (refsize);
|
||||
rsz -= baseoff;
|
||||
if (known_lt (tree_to_poly_int64 (memsize), rsz))
|
||||
memsize = wide_int_to_tree (TREE_TYPE (memsize), rsz);
|
||||
}
|
||||
|
||||
baseoff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (!memsize)
|
||||
{
|
||||
if (typematch)
|
||||
{
|
||||
if (DECL_P (base)
|
||||
&& DECL_EXTERNAL (base)
|
||||
&& bt == basetype
|
||||
&& !*interior_zero_length)
|
||||
/* The size of a flexible array member of an extern struct
|
||||
with no initializer cannot be determined (it's defined
|
||||
in another translation unit and can have an initializer
|
||||
witth an arbitrary number of elements). */
|
||||
return NULL_TREE;
|
||||
|
||||
/* Use the size of the base struct or, for interior zero-length
|
||||
arrays, the size of the enclosing type. */
|
||||
memsize = TYPE_SIZE_UNIT (bt);
|
||||
}
|
||||
else
|
||||
/* Use the size of the BASE object (possibly an array of some
|
||||
other type such as char used to store the struct). */
|
||||
memsize = DECL_SIZE_UNIT (base);
|
||||
}
|
||||
|
||||
/* If the flexible array member has a known size use the greater
|
||||
of it and the tail padding in the enclosing struct.
|
||||
Otherwise, when the size of the flexible array member is unknown
|
||||
and the referenced object is not a struct, use the size of its
|
||||
type when known. This detects sizes of array buffers when cast
|
||||
to struct types with flexible array members. */
|
||||
if (memsize)
|
||||
{
|
||||
poly_int64 memsz64 = memsize ? tree_to_poly_int64 (memsize) : 0;
|
||||
if (known_lt (baseoff, memsz64))
|
||||
{
|
||||
memsz64 -= baseoff;
|
||||
return wide_int_to_tree (TREE_TYPE (memsize), memsz64);
|
||||
}
|
||||
return integer_zero_node;
|
||||
}
|
||||
|
||||
/* Return "don't know" for an external non-array object since its
|
||||
flexible array member can be initialized to have any number of
|
||||
elements. Otherwise, return zero because the flexible array
|
||||
member has no elements. */
|
||||
return (DECL_EXTERNAL (base) && TREE_CODE (TREE_TYPE (base)) != ARRAY_TYPE
|
||||
return (DECL_P (base)
|
||||
&& DECL_EXTERNAL (base)
|
||||
&& (!typematch
|
||||
|| TREE_CODE (basetype) != ARRAY_TYPE)
|
||||
? NULL_TREE : integer_zero_node);
|
||||
}
|
||||
|
||||
|
@ -5262,7 +5262,7 @@ extern tree component_ref_field_offset (tree);
|
||||
of an initialized flexible array member. The size might be zero for
|
||||
an object with an uninitialized flexible array member or null if it
|
||||
cannot be determined. */
|
||||
extern tree component_ref_size (tree);
|
||||
extern tree component_ref_size (tree, bool * = NULL);
|
||||
|
||||
extern int tree_map_base_eq (const void *, const void *);
|
||||
extern unsigned int tree_map_base_hash (const void *);
|
||||
|
@ -852,6 +852,8 @@ inline HOST_WIDE_INT
|
||||
generic_wide_int <storage>::sign_mask () const
|
||||
{
|
||||
unsigned int len = this->get_len ();
|
||||
gcc_assert (len > 0);
|
||||
|
||||
unsigned HOST_WIDE_INT high = this->get_val ()[len - 1];
|
||||
if (!is_sign_extended)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user