consider offsets when handling nonstrings in -Wstringop-truncation (PR 85643)

Message ID aaf2b20e-8adf-55cd-2bef-682d26d3bcc8@gmail.com
State New
Headers show
Series
  • consider offsets when handling nonstrings in -Wstringop-truncation (PR 85643)
Related show

Commit Message

Martin Sebor May 11, 2018, 4:21 p.m.
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

Comments

Jeff Law May 14, 2018, 9:17 p.m. | #1
On 05/11/2018 10:21 AM, Martin Sebor wrote:
> 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
> 
> gcc-85643.diff
> 
> 
> 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.
OK for the trunk.  It's borderline for the release branch, but I'll ack
it there too after a week of soak time on the trunk.

jeff

Patch

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;
+}