Message ID | 8d56ad7d-88d9-b5b9-35da-4d7fadf2ec00@gmail.com |
---|---|
State | New |
Headers | show |
Series | avoid assuming arrays have nonzero size (PR 88956) | expand |
On Tue, 22 Jan 2019, Martin Sebor wrote: > PS In GCC 10, unless there is an important use case that escapes > me, I think GCC should warn for zero-length non-member array > objects, or perhaps even for internal struct members (those followed > by another member). Not to avoid these sorts of bugs but because > they seem too dangerous to use safely. I think one expected use case of zero-size objects is for e.g. a structure that is zero-size in some configurations of the code and non-zero-size on other configurations (but where it's most convenient to have the variables, struct members, etc. exist unconditionally). It's quite possible that arrays of such objects may be constructed in such code.
Ping: https://gcc.gnu.org/ml/gcc-patches/2019-01/msg01340.html This is a straightforward fix for an ICE. I will commit it tomorrow unless there are suggestions for other changes. On 1/22/19 6:18 PM, Martin Sebor wrote: > The enhancement to treat char initializer-lists as STRING_CSTs > committed earlier last year introduced an assumption that array > elements have a non-zero size. As it turns out, the zero-length > array extension that makes it possible to define even multi- > dimensional zero-length array objects breaks that assumption when > it's passed as an argument to a function like memcpy. The attached > patch removes that assumption. > > Tested on x86_64-linux. > > Martin > > PS In GCC 10, unless there is an important use case that escapes > me, I think GCC should warn for zero-length non-member array > objects, or perhaps even for internal struct members (those followed > by another member). Not to avoid these sorts of bugs but because > they seem too dangerous to use safely.
Martin Sebor <msebor@gmail.com> writes: > Ping: https://gcc.gnu.org/ml/gcc-patches/2019-01/msg01340.html > > This is a straightforward fix for an ICE. I will commit it tomorrow > unless there are suggestions for other changes. That's not how it works. Please wait for the patch to be approved by someone. Thanks, Richard
On 1/29/19 5:44 AM, Richard Sandiford wrote: > Martin Sebor <msebor@gmail.com> writes: >> Ping: https://gcc.gnu.org/ml/gcc-patches/2019-01/msg01340.html >> >> This is a straightforward fix for an ICE. I will commit it tomorrow >> unless there are suggestions for other changes. > > That's not how it works. Please wait for the patch to be approved > by someone. The rules are explicit that "Obvious fixes can be committed without prior approval." I consider moving an equality test three lines up an obvious fix. Martin
On Tue, Jan 22, 2019 at 06:18:28PM -0700, Martin Sebor wrote: > PS In GCC 10, unless there is an important use case that escapes > me, I think GCC should warn for zero-length non-member array > objects, or perhaps even for internal struct members (those followed > by another member). Not to avoid these sorts of bugs but because > they seem too dangerous to use safely. No, we shouldn't warn. > --- gcc/gimple-fold.c (revision 268086) > +++ gcc/gimple-fold.c (working copy) > @@ -6715,12 +6715,14 @@ fold_array_ctor_reference (tree type, tree ctor, > elt_size = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))); > > /* When TYPE is non-null, verify that it specifies a constant-sized > - accessed not larger than size of array element. */ > - if (type > - && (!TYPE_SIZE_UNIT (type) > - || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST > - || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type)) > - || elt_size == 0)) > + accessed not larger than size of array element. Avoid using zero > + ELT_SIZE, the result of an empty initializer for a zero-length > + array. */ The comment is misleading, there are many reasons why you could have zero elt_size, C struct S {}, or int x[10][0], etc. Just don't change anything in the comment at all, or say Punt if element size is zero to avoid division by zero. or something similar. > + if (elt_size == 0 > + || (type > + && (!TYPE_SIZE_UNIT (type) > + || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST > + || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type))))) > return NULL_TREE; Otherwise LGTM. If you could fix also the two comments a few lines above this: /* Static constructors for variably sized objects makes no sense. */ to /* Static constructors for variably sized objects make no sense. */ it would be appreciated. Jakub
On 1/29/19 11:23 AM, Jakub Jelinek wrote: >> --- gcc/gimple-fold.c (revision 268086) >> +++ gcc/gimple-fold.c (working copy) >> @@ -6715,12 +6715,14 @@ fold_array_ctor_reference (tree type, tree ctor, >> elt_size = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))); >> >> /* When TYPE is non-null, verify that it specifies a constant-sized >> - accessed not larger than size of array element. */ >> - if (type >> - && (!TYPE_SIZE_UNIT (type) >> - || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST >> - || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type)) >> - || elt_size == 0)) >> + accessed not larger than size of array element. Avoid using zero >> + ELT_SIZE, the result of an empty initializer for a zero-length >> + array. */ > > The comment is misleading, there are many reasons why you could have > zero elt_size, C struct S {}, or int x[10][0], etc. Just don't change > anything in the comment at all, or say > Punt if element size is zero to avoid division by zero. > or something similar. Thanks. The goal of the comment is to give an example of the unusual case when the size of an array element may be zero, not suggest there is just one such case, or enumerate all all of them. I've adjusted the text and added tests for the empty zero struct. > >> + if (elt_size == 0 >> + || (type >> + && (!TYPE_SIZE_UNIT (type) >> + || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST >> + || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type))))) >> return NULL_TREE; > > Otherwise LGTM. > > If you could fix also the two comments a few lines above this: > /* Static constructors for variably sized objects makes no sense. */ > to > /* Static constructors for variably sized objects make no sense. */ > it would be appreciated. Sure, I don't mind doing that. Committed in r268378. Martin
PR middle-end/88956 - ICE: Floating point exception on a memcpy from an zero-length constant array gcc/ChangeLog: PR c/88956 * gimple-fold.c (fold_array_ctor_reference): Avoid zero-length arrays. gcc/testsuite/ChangeLog: PR c/88956 * gcc.dg/Warray-bounds-39.c: New test. Index: gcc/gimple-fold.c =================================================================== --- gcc/gimple-fold.c (revision 268086) +++ gcc/gimple-fold.c (working copy) @@ -6715,12 +6715,14 @@ fold_array_ctor_reference (tree type, tree ctor, elt_size = wi::to_offset (TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (ctor)))); /* When TYPE is non-null, verify that it specifies a constant-sized - accessed not larger than size of array element. */ - if (type - && (!TYPE_SIZE_UNIT (type) - || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST - || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type)) - || elt_size == 0)) + accessed not larger than size of array element. Avoid using zero + ELT_SIZE, the result of an empty initializer for a zero-length + array. */ + if (elt_size == 0 + || (type + && (!TYPE_SIZE_UNIT (type) + || TREE_CODE (TYPE_SIZE_UNIT (type)) != INTEGER_CST + || elt_size < wi::to_offset (TYPE_SIZE_UNIT (type))))) return NULL_TREE; /* Compute the array index we look for. */ Index: gcc/testsuite/gcc.dg/Warray-bounds-39.c =================================================================== --- gcc/testsuite/gcc.dg/Warray-bounds-39.c (nonexistent) +++ gcc/testsuite/gcc.dg/Warray-bounds-39.c (working copy) @@ -0,0 +1,115 @@ +/* PR middle-end/88956 - ICE: Floating point exception on a memcpy from + an zero-length constant array + Verify both that memory and string calls with a zero-length array + don't cause an ICE, and also that they emit warnings. + { dg-do compile } + { dg-options "-O2 -Wall" } */ + +typedef __SIZE_TYPE__ size_t; + +extern void* memcpy (void*, const void*, size_t); +extern void* memmove (void*, const void*, size_t); +extern char* strcpy (char*, const char*); +extern char* strncpy (char*, const char*, size_t); + +const char s0[0] = { }; +const char s0_0[0][0] = { }; +const char s0_1[0][1] = { }; +const char s1_0[1][0] = { }; + +char d[4]; + +void* test_memcpy_s0_1 (void *d) +{ + return memcpy (d, s0, 1); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memcpy_s0_2 (void *d) +{ + return memcpy (d, s0, 2); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memcpy_s0_0_1 (void *d) +{ + return memcpy (d, s0_0, 1); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memcpy_s0_0_2 (void *d) +{ + return memcpy (d, s0_0, 2); /* { dg-warning "\\\[-Warray-bounds" } */ +} + + +void* test_memcpy_s0_1_1 (void *d) +{ + return memcpy (d, s0_1, 1); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memcpy_s0_1_2 (void *d) +{ + return memcpy (d, s0_1, 2); /* { dg-warning "\\\[-Warray-bounds" } */ +} + + +void* test_memcpy_s1_0_1 (void *d) +{ + return memcpy (d, s1_0, 1); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memcpy_s1_0_2 (void *d) +{ + return memcpy (d, s1_0, 2); /* { dg-warning "\\\[-Warray-bounds" } */ +} + + +void* test_memmove_s0_1 (void *d) +{ + return memmove (d, s0, 1); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memmove_s0_2 (void *d) +{ + return memmove (d, s0, 2); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memmove_s0_0_1 (void *d) +{ + return memmove (d, s0_0, 1); /* { dg-warning "\\\[-Warray-bounds" } */ +} + +void* test_memmove_s0_0_2 (void *d) +{ + return memmove (d, s0_0, 2); /* { dg-warning "\\\[-Warray-bounds" } */ +} + + +char* test_strcpy_s0 (char *d) +{ + return strcpy (d, s0); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */ +} + +char* test_strcpy_s0_0 (char *d) +{ + return strcpy (d, s0_0[0]); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */ +} + + +char* test_strncpy_s0_1 (char *d) +{ + return strncpy (d, s0, 1); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */ +} + +char* test_strncpy_s0_2 (char *d) +{ + return strncpy (d, s0, 2); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */ +} + +char* test_strncpy_s0_0_1 (char *d) +{ + return strncpy (d, s0_0[0], 1); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */ +} + +char* test_strncpy_s0_0_2 (char *d) +{ + return strncpy (d, s0_0[0], 2); /* { dg-warning "\\\[-Warray-bounds" "pr88991" { xfail *-*-* } } */ +}