This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] avoid false positives due to signed to unsigned conversion (PR 78973)


When the size passed to a call to a function like memcpy is a signed
integer whose range has a negative lower bound and a positive upper
bound the lower bound of the range of the argument after conversion
to size_t may be in excess of the maximum object size (PTRDIFF_MAX
by default).  This results in -Wstringop-overflow false positives.

The attached patch detects this case and avoids the problem.

Btw., I had a heck of a time creating a test case for this.  The
large translation unit submitted with the bug is from a file in
the Linux kernel of some complexity.  There, the range of the int
variable (before conversion to size_t) is [INT_MIN, INT_MAX].  It
seems very difficult to create a VR_RANGE for a signed int that
matches it.  The test case I came up with that still reproduces
the false positive crates an anti-range for the signed int argument
by converting an unsigned int in one range to a signed int and
constraining it to another range.  The false positive is avoided
because the code doesn't (yet) handle anti-ranges.

Martin

PS This seems lie a bug or gotcha in the get_range_info() function.
In the regression test added by the patch the VRP dump shows the
following:

  n.0_1: ~[0, 4]
  _6: [18446744071562067968, +INF]

  ...

  _6 = (long unsigned int) n.0_1;
  __builtin_memset (d_5(D), 0, _6);

but get_range_info(_6) returns the VR_RANGE:

  [ 0xffffffff:80000000, 0xffffffff:ffffffff ]

That doesn't seem right.  Is there a better/more appropriate way
to determine the "correct" range?  If not, perhaps get_range_info
should be enhanced to make it possible to call it to detect this
conversion and report a more correct result (e.g., based on
a new, optional argument).

Martin
PR c/78973 - [7.0 regression] warning: â??memcpyâ??: specified size between 18446744071562067968 and 18446744073709551615 exceeds maximum object size 9223372036854775807 [-Wstringop-overflow=]

gcc/ChangeLog:

	PR c/78973
	* builtins.c (get_size_range): Handle signed to unsigned conversion.

gcc/testsuite/ChangeLog:

	PR c/78973
	* gcc.dg/pr78973.c: New test.

diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5b76dfd..883d25c 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -3051,9 +3051,26 @@ get_size_range (tree exp, tree range[2])
 
       if (range_type == VR_RANGE)
 	{
+	  /* The range can be the result of a conversion of a signed
+	     variable to size_t with the lower bound after conversion
+	     corresponding to a negative lower bound of the original
+	     variable.  Avoid the false positive for this case.  */
+	  gimple *def = SSA_NAME_DEF_STMT (exp);
+	  if (is_gimple_assign (def))
+	    {
+	      tree_code code = gimple_assign_rhs_code (def);
+	      if (code == NOP_EXPR)
+		{
+		  tree rhs = gimple_assign_rhs1 (def);
+		  if (!TYPE_UNSIGNED (TREE_TYPE (rhs)))
+		    return get_size_range (rhs, range);
+		}
+	    }
+
 	  /* Interpret the bound in the variable's type.  */
 	  range[0] = wide_int_to_tree (TREE_TYPE (exp), min);
 	  range[1] = wide_int_to_tree (TREE_TYPE (exp), max);
+
 	  return true;
 	}
       else if (range_type == VR_ANTI_RANGE)
diff --git a/gcc/testsuite/gcc.dg/pr78973.c b/gcc/testsuite/gcc.dg/pr78973.c
new file mode 100644
index 0000000..ef212cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr78973.c
@@ -0,0 +1,18 @@
+/* PR c/78973 - [7.0 regression] warning: â??memcpyâ??: specified size between
+   18446744071562067968 and 18446744073709551615 exceeds maximum object
+   size 9223372036854775807 [-Wstringop-overflow=]
+   { dg-do compile }
+   { dg-options "-O2 -Wall" }  */
+
+void f (void *p, int n)
+{
+  if (n <= 4)
+    __builtin_memset (p, 0, n);   /* { dg-bogus "exceeds maximum object size" } */
+}
+
+void g (void *d, unsigned n)
+{
+  if (n < 5)
+    n = 5;
+  f (d, n);
+}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]