diff mbox

avoid eliminating snprintf(d, n, ...) whose zero size comes from a range (PR 79496)

Message ID 62da7958-6152-d23a-bd05-f96bcb19b482@gmail.com
State New
Headers show

Commit Message

Martin Sebor Feb. 13, 2017, 8:11 p.m. UTC
When the size of the destination in a call to snprintf is in
a range, at level 1 -Wformat-truncation uses the upper bound
as the size while the stricter level 2 uses the lower bound.
However, when the lower bound is zero treating it the same as
a constant zero and optimizing the call into a constant isn't
correct because the actual argument need not be zero and the
output of the function is important.  The attached patch
avoids this unsafe transformation.

Is this okay for trunk?

Martin

Comments

Jeff Law Feb. 13, 2017, 9:30 p.m. UTC | #1
On 02/13/2017 01:11 PM, Martin Sebor wrote:
> When the size of the destination in a call to snprintf is in
> a range, at level 1 -Wformat-truncation uses the upper bound
> as the size while the stricter level 2 uses the lower bound.
> However, when the lower bound is zero treating it the same as
> a constant zero and optimizing the call into a constant isn't
> correct because the actual argument need not be zero and the
> output of the function is important.  The attached patch
> avoids this unsafe transformation.
>
> Is this okay for trunk?
>
> Martin
>
> gcc-79496.diff
>
>
> PR middle-end/79496 - call to snprintf with zero size eliminated with -Wformat-truncation=2
>
> gcc/ChangeLog:
>
> 	PR middle-end/79496
> 	* gimple-ssa-sprintf.c (pass_sprintf_length::handle_gimple_call): Avoid
> 	clearing info.nowrite flag when snprintf size argument is a range.
>
> gcc/testsuite/ChangeLog:
>
> 	PR middle-end/79496
> 	* gcc.dg/tree-ssa/builtin-snprintf-2.c: New test.
OK.
jeff
diff mbox

Patch

PR middle-end/79496 - call to snprintf with zero size eliminated with -Wformat-truncation=2

gcc/ChangeLog:

	PR middle-end/79496
	* gimple-ssa-sprintf.c (pass_sprintf_length::handle_gimple_call): Avoid
	clearing info.nowrite flag when snprintf size argument is a range.

gcc/testsuite/ChangeLog:

	PR middle-end/79496
	* gcc.dg/tree-ssa/builtin-snprintf-2.c: New test.

diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index bf76162..1079a41 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -3452,6 +3452,10 @@  pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
 
   info.format = gimple_call_arg (info.callstmt, idx_format);
 
+  /* True when the destination size is constant as opposed to the lower
+     or upper bound of a range.  */
+  bool dstsize_cst_p = true;
+
   if (idx_dstsize == HOST_WIDE_INT_M1U)
     {
       /* For non-bounded functions like sprintf, determine the size
@@ -3492,8 +3496,8 @@  pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
       else if (TREE_CODE (size) == SSA_NAME)
 	{
 	  /* Try to determine the range of values of the argument
-	     and use the greater of the two at -Wformat-level 1 and
-	     the smaller of them at level 2.  */
+	     and use the greater of the two at level 1 and the smaller
+	     of them at level 2.  */
 	  wide_int min, max;
 	  enum value_range_type range_type
 	    = get_range_info (size, &min, &max);
@@ -3504,6 +3508,11 @@  pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
 		   ? wi::fits_uhwi_p (max) ? max.to_uhwi () : max.to_shwi ()
 		   : wi::fits_uhwi_p (min) ? min.to_uhwi () : min.to_shwi ());
 	    }
+
+	  /* The destination size is not constant.  If the function is
+	     bounded (e.g., snprintf) a lower bound of zero doesn't
+	     necessarily imply it can be eliminated.  */
+	  dstsize_cst_p = false;
 	}
     }
 
@@ -3520,7 +3529,7 @@  pass_sprintf_length::handle_gimple_call (gimple_stmt_iterator *gsi)
 	 without actually producing any.  Pretend the size is
 	 unlimited in this case.  */
       info.objsize = HOST_WIDE_INT_MAX;
-      info.nowrite = true;
+      info.nowrite = dstsize_cst_p;
     }
   else
     {
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-2.c b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-2.c
new file mode 100644
index 0000000..a192aee
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-snprintf-2.c
@@ -0,0 +1,24 @@ 
+/* PR middle-end/79496 - call to snprintf with non-zero size eliminated
+   with -Wformat-truncation=2
+   { dg-do compile }
+   { dg-options "-O2 -Wall -Wformat-truncation=2 -fprintf-return-value -fdump-tree-optimized" } */
+
+char d[2];
+
+int test_cst (unsigned n)
+{
+  if (1 < n)
+    n = 0;
+
+  return __builtin_snprintf (d, n, "%d", 1);
+}
+
+int test_var (char *d, unsigned n)
+{
+  if (2 < n)
+    n = 0;
+
+  return __builtin_snprintf (d, n, "%i", 1);
+}
+
+/* { dg-final { scan-tree-dump-times "snprintf" 2 "optimized"} } */