The attached tweak suppresses some -Wstringop-truncation false positives when a pointer into an array declared nonstring is passed to a function that expects a string argument such as in:
char a[8] __attribute__ ((nonstring)); strncpy (a + 1, s, sizeof a - 1); I'd like to commit this fix to both trunk and 8-branch. Thanks Martin
PR middle-end/85643 - attribute nonstring fails to squash -Wstringop-truncation warning gcc/ChangeLog: PR middle-end/85643 * calls.c (get_attr_nonstring_decl): Handle MEM_REF. gcc/testsuite/ChangeLog: PR middle-end/85643 * c-c++-common/attr-nonstring-7.c: New test. diff --git a/gcc/calls.c b/gcc/calls.c index f5c8ad4..d2eecf1 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -1587,8 +1587,12 @@ get_attr_nonstring_decl (tree expr, tree *ref) if (ref) *ref = decl; - if (TREE_CODE (decl) == COMPONENT_REF) + if (TREE_CODE (decl) == ARRAY_REF) + decl = TREE_OPERAND (decl, 0); + else if (TREE_CODE (decl) == COMPONENT_REF) decl = TREE_OPERAND (decl, 1); + else if (TREE_CODE (decl) == MEM_REF) + return get_attr_nonstring_decl (TREE_OPERAND (decl, 0), ref); if (DECL_P (decl) && lookup_attribute ("nonstring", DECL_ATTRIBUTES (decl))) diff --git a/gcc/testsuite/c-c++-common/attr-nonstring-7.c b/gcc/testsuite/c-c++-common/attr-nonstring-7.c new file mode 100644 index 0000000..a32cbfe --- /dev/null +++ b/gcc/testsuite/c-c++-common/attr-nonstring-7.c @@ -0,0 +1,90 @@ +/* PR 85643 - attribute nonstring fails to squash -Wstringop-truncation + warning + { dg-do compile } + { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + +#define strncpy __builtin_strncpy + +struct A { + char a[16 + 1]; +}; + +struct B { + char a[16] __attribute__ ((__nonstring__)); +}; + +struct B* +test_memarray (const struct A *s) +{ + static struct B b; + strncpy (b.a, s->a, sizeof b.a); + return &b; +} + +const char* +test_array (const char *s) +{ + static char a[80] __attribute__ ((__nonstring__)); + strncpy (a, s, sizeof a); + return a; +} + +const char* +test_array_idx (const char *s) +{ + static char a[80] __attribute__ ((__nonstring__)); + char *p __attribute__ ((__nonstring__)) = &a[20]; + strncpy (p, s, 60); /* { dg-bogus "-Wstringop-truncation" } */ + return a; +} + +const char* +test_array_off (const char *s) +{ + static char a[80] __attribute__ ((__nonstring__)); + char *p __attribute__ ((__nonstring__)) = a + 20; + strncpy (p, s, 60); /* { dg-bogus "-Wstringop-truncation" } */ + return a; +} + +struct B* +test_memarray_cstidx_idx (const char *s) +{ + static struct B b[2]; + char *p __attribute__ ((__nonstring__)) = &b[1].a[4]; + + /* The destination below is represented as &MEM[(void *)&a + 20B] and + which (in general) doesn't make it possible to determine what member + it refers to. */ + strncpy (p, s, sizeof b[1].a - 4); /* { dg-bogus "-Wstringop-truncation" "" { xfail *-*-*} } */ + return b; +} + +struct B* +test_memarray_cstidx_off (const char *s) +{ + static struct B b[2]; + char *p __attribute__ ((__nonstring__)) = b[1].a + 4; + + /* Same as above. */ + strncpy (p, s, sizeof b[1].a - 4); /* { dg-bogus "-Wstringop-truncation" "" { xfail *-*-*} } */ + return b; +} + +struct B* +test_memarray_varidx_idx (const char *s, int i) +{ + static struct B b[3]; + char *p __attribute__ ((__nonstring__)) = &b[i].a[4]; + strncpy (p, s, sizeof b[i].a - 4); + return b; +} + +struct B* +test_memarray_varidx_off (const char *s, int i) +{ + static struct B b[3]; + char *p __attribute__ ((__nonstring__)) = b[i].a + 4; + strncpy (p, s, sizeof b[i].a - 4); + return b; +}