Warning for a strncpy call whose bound is the same as the size
of the source and suggesting to use the size of the source is
less than helpful when both sizes are the same, as in:

  char a[4], b[4];
  strncpy (a, b, sizeof b);

The attached patch suppresses the -Wsizeof-pointer-memaccess
warning for these cases.  To do that even for VLAs (in some
cases), the patch enhances operand_equal_p() to handle
SAVE_EXPR to detect when VLA in sizeof VLA refers to the size
of a variable-length array.

Is this okay for trunk and GCC 8?

Martin
PR c/85931 -  -Wsizeof-pointer-memaccess for strncpy with size of source

gcc/c-family/ChangeLog:

	PR c/85931
	* c-warn.c (sizeof_pointer_memaccess_warning): Avoid warning when
	sizeof source and destination yields the same value.

gcc/ChangeLog:

	PR c/85931
	* fold-const.c (operand_equal_p): Handle SAVE_EXPR.

gcc/testsuite/ChangeLog:

	PR c/85931
	* gcc.dg/Wstringop-truncation-3.c: New test.

diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index e7bcbb1..96a56d4 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -792,13 +792,31 @@ sizeof_pointer_memaccess_warning (location_t *sizeof_arg_loc, tree callee,
     {
       /* The argument type may be an array.  Diagnose bounded string
 	 copy functions that specify the bound in terms of the source
-	 argument rather than the destination.  */
+	 argument rather than the destination unless they are equal
+	 to one another.  Handle constant sizes and also try to handle
+	 sizeof expressions involving VLAs.  */
       if (strop && !cmp && fncode != BUILT_IN_STRNDUP && src)
 	{
 	  tem = tree_strip_nop_conversions (src);
 	  if (TREE_CODE (tem) == ADDR_EXPR)
 	    tem = TREE_OPERAND (tem, 0);
-	  if (operand_equal_p (tem, sizeof_arg[idx], OEP_ADDRESS_OF))
+
+	  tree d = tree_strip_nop_conversions (dest);
+	  if (TREE_CODE (d) == ADDR_EXPR)
+	    d = TREE_OPERAND (d, 0);
+
+	  tree dstsz = TYPE_SIZE_UNIT (TREE_TYPE (d));
+	  tree srcsz = TYPE_SIZE_UNIT (TREE_TYPE (tem));
+
+	  if ((!dstsz
+	       || !srcsz
+	       || (TREE_CODE (dstsz) != INTEGER_CST
+		   && TREE_CODE (srcsz) != INTEGER_CST
+		   && !operand_equal_p (dstsz, srcsz, OEP_LEXICOGRAPHIC))
+	       || (TREE_CODE (dstsz) == INTEGER_CST
+		   && TREE_CODE (srcsz) == INTEGER_CST
+		   && !tree_int_cst_equal (dstsz, srcsz)))
+	      && operand_equal_p (tem, sizeof_arg[idx], OEP_ADDRESS_OF))
 	    warning_at (sizeof_arg_loc[idx], OPT_Wsizeof_pointer_memaccess,
 			"argument to %<sizeof%> in %qD call is the same "
 			"expression as the source; did you mean to use "
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index 3258aad..ead6e53 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -3358,6 +3358,7 @@ operand_equal_p (const_tree arg0, const_tree arg1, unsigned int flags)
 
 	case CLEANUP_POINT_EXPR:
 	case EXPR_STMT:
+	case SAVE_EXPR:
 	  if (flags & OEP_LEXICOGRAPHIC)
 	    return OP_SAME (0);
 	  return 0;
diff --git a/gcc/testsuite/gcc.dg/Wstringop-truncation-3.c b/gcc/testsuite/gcc.dg/Wstringop-truncation-3.c
new file mode 100644
index 0000000..57f4d64
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wstringop-truncation-3.c
@@ -0,0 +1,59 @@
+/* PR c/85931 - -Wsizeof-pointer-memaccess for strncpy with size of source
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wstringop-truncation -ftrack-macro-expansion=0" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+extern char* strncpy (char*, const char*, size_t);
+
+extern char a3[3], b3[3];
+extern char a5[5], b5[5];
+extern char ax[], bx[];
+
+struct SA
+{
+  char a3[3], b3[3];
+  char a5[5], b5[5];
+  char ax[];
+};
+
+void sink (void*, ...);
+
+#define T(d, s, n)   sink (strncpy (d, s, n))
+
+void test_array (unsigned n)
+{
+  T (a3, b3, 3);
+  /* For the following statemenmt, GCC 8.1 issues warning:
+
+       argument to ‘sizeof’ in ‘strncpy’ call is the same expression
+       as the source; did you mean to use the size of the destination?
+
+     Since the size of both the source and destination the warning
+     isn't helpful.  Verify that it isn't issued.  */
+  T (a3, b3, sizeof b3);    /* { dg-bogus "\\\[-Wsizeof-pointer-memaccess" } */
+
+  T (a3, ax, sizeof a3);    /* { dg-warning "\\\[-Wstringop-truncation" } */
+  T (ax, a3, sizeof a3);    /* { dg-warning "argument to .sizeof. in .strncpy. call is the same expression as the source" } */
+
+  char an[n], bn[n];
+  sink (an, bn);
+
+  T (an, bn, sizeof bn);    /* { dg-bogus "\\\[-Wsizeof-pointer-memaccess" } */
+}
+
+void test_member_array (struct SA *sa, unsigned n)
+{
+  T (sa->a3, sa->b3, 3);
+  T (sa->a3, sa->b3, sizeof sa->b3);  /* { dg-bogus "\\\[-Wsizeof-pointer-memaccess" } */
+
+  T (sa->a3, sa->ax, sizeof sa->a3);  /* { dg-warning "\\\[-Wstringop-truncation" } */
+  T (sa->ax, sa->a3, sizeof sa->a3);  /* { dg-warning "argument to .sizeof. in .strncpy. call is the same expression as the source" } */
+
+  struct VarLenStruct {
+    char an[n], bn[n];
+  } x;
+
+  sink (&x);
+  T (x.an, x.bn, sizeof x.bn);        /* { dg-bogus "\\\[-Wsizeof-pointer-memaccess" } */
+}

Reply via email to