diff mbox

Avoid -fprintf-return-value from optimizing away snprintf (0, 0, "...%n...", ...) (PR tree-optimization/78965)

Message ID 20170102193634.GJ21933@tucnak
State New
Headers show

Commit Message

Jakub Jelinek Jan. 2, 2017, 7:36 p.m. UTC
Hi!

Even when we know the exact return value of a snprintf call with 0 length
(i.e. one that doesn't write anything into a buffer), there can be %n
directives in the format string that have side-effects that shouldn't be
discarded.

The following patch avoids the replacement of the snprintf call
with just the constant if there is any %n directive.

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2017-01-02  Jakub Jelinek  <jakub@redhat.com>

	PR tree-optimization/78965
	* gimple-ssa-sprintf.c (pass_sprintf_length::compute_format_length):
	Change first argument from const call_info & to call_info &.  For %n
	set info.nowrite to false.

	* gcc.dg/pr78965.c: New test.


	Jakub

Comments

Martin Sebor Jan. 2, 2017, 10:51 p.m. UTC | #1
On 01/02/2017 12:36 PM, Jakub Jelinek wrote:
> Hi!
>
> Even when we know the exact return value of a snprintf call with 0 length
> (i.e. one that doesn't write anything into a buffer), there can be %n
> directives in the format string that have side-effects that shouldn't be
> discarded.
>
> The following patch avoids the replacement of the snprintf call
> with just the constant if there is any %n directive.
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

Thanks.  The fix looks good to me.  I would suggest to also update
the comment above the nowrite member to say something like this:

   /* True for bounded functions like snprintf that specify a zero-size
      buffer as a request to compute the size of output without actually
      writing any.  NOWRITE is cleared in response to the %n directive
      which has side-effects similar to writing output.  */

Martin

>
> 2017-01-02  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR tree-optimization/78965
> 	* gimple-ssa-sprintf.c (pass_sprintf_length::compute_format_length):
> 	Change first argument from const call_info & to call_info &.  For %n
> 	set info.nowrite to false.
>
> 	* gcc.dg/pr78965.c: New test.
>
> --- gcc/gimple-ssa-sprintf.c.jj	2017-01-01 12:45:35.000000000 +0100
> +++ gcc/gimple-ssa-sprintf.c	2017-01-02 12:09:29.902945255 +0100
> @@ -131,7 +131,7 @@ public:
>    void handle_gimple_call (gimple_stmt_iterator*);
>
>    struct call_info;
> -  bool compute_format_length (const call_info &, format_result *);
> +  bool compute_format_length (call_info &, format_result *);
>  };
>
>  bool
> @@ -2357,7 +2357,7 @@ add_bytes (const pass_sprintf_length::ca
>     that caused the processing to be terminated early).  */
>
>  bool
> -pass_sprintf_length::compute_format_length (const call_info &info,
> +pass_sprintf_length::compute_format_length (call_info &info,
>  					    format_result *res)
>  {
>    /* The variadic argument counter.  */
> @@ -2624,6 +2624,9 @@ pass_sprintf_length::compute_format_leng
>  	  return false;
>
>  	case 'n':
> +	  /* %n has side-effects even when nothing is actually printed to
> +	     any buffer.  */
> +	  info.nowrite = false;
>  	  break;
>
>  	case 'c':
> --- gcc/testsuite/gcc.dg/pr78965.c.jj	2017-01-02 12:12:15.959803429 +0100
> +++ gcc/testsuite/gcc.dg/pr78965.c	2017-01-02 12:11:06.000000000 +0100
> @@ -0,0 +1,14 @@
> +/* PR tree-optimization/78965 */
> +/* { dg-do run { target c99_runtime } } */
> +/* { dg-options "-O2" } */
> +/* { dg-add-options c99_runtime } */
> +
> +int
> +main ()
> +{
> +  int a = 5, b = 6;
> +  int c = __builtin_snprintf (0, 0, "a%nb%nc", &a, &b);
> +  if (a + b + c != 6)
> +    __builtin_abort ();
> +  return 0;
> +}
>
> 	Jakub
>
Jakub Jelinek Jan. 2, 2017, 10:56 p.m. UTC | #2
On Mon, Jan 02, 2017 at 03:51:14PM -0700, Martin Sebor wrote:
> On 01/02/2017 12:36 PM, Jakub Jelinek wrote:
> > Hi!
> > 
> > Even when we know the exact return value of a snprintf call with 0 length
> > (i.e. one that doesn't write anything into a buffer), there can be %n
> > directives in the format string that have side-effects that shouldn't be
> > discarded.
> > 
> > The following patch avoids the replacement of the snprintf call
> > with just the constant if there is any %n directive.
> > 
> > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
> 
> Thanks.  The fix looks good to me.  I would suggest to also update
> the comment above the nowrite member to say something like this:
> 
>   /* True for bounded functions like snprintf that specify a zero-size
>      buffer as a request to compute the size of output without actually
>      writing any.  NOWRITE is cleared in response to the %n directive
>      which has side-effects similar to writing output.  */

LGTM, thanks.  I'll adjust the comment if it is approved.

> > 2017-01-02  Jakub Jelinek  <jakub@redhat.com>
> > 
> > 	PR tree-optimization/78965
> > 	* gimple-ssa-sprintf.c (pass_sprintf_length::compute_format_length):
> > 	Change first argument from const call_info & to call_info &.  For %n
> > 	set info.nowrite to false.
> > 
> > 	* gcc.dg/pr78965.c: New test.

	Jakub
Richard Biener Jan. 3, 2017, 6:41 a.m. UTC | #3
On January 2, 2017 8:36:34 PM GMT+01:00, Jakub Jelinek <jakub@redhat.com> wrote:
>Hi!
>
>Even when we know the exact return value of a snprintf call with 0
>length
>(i.e. one that doesn't write anything into a buffer), there can be %n
>directives in the format string that have side-effects that shouldn't
>be
>discarded.
>
>The following patch avoids the replacement of the snprintf call
>with just the constant if there is any %n directive.
>
>Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

Richard.

>2017-01-02  Jakub Jelinek  <jakub@redhat.com>
>
>	PR tree-optimization/78965
>	* gimple-ssa-sprintf.c (pass_sprintf_length::compute_format_length):
>	Change first argument from const call_info & to call_info &.  For %n
>	set info.nowrite to false.
>
>	* gcc.dg/pr78965.c: New test.
>
>--- gcc/gimple-ssa-sprintf.c.jj	2017-01-01 12:45:35.000000000 +0100
>+++ gcc/gimple-ssa-sprintf.c	2017-01-02 12:09:29.902945255 +0100
>@@ -131,7 +131,7 @@ public:
>   void handle_gimple_call (gimple_stmt_iterator*);
> 
>   struct call_info;
>-  bool compute_format_length (const call_info &, format_result *);
>+  bool compute_format_length (call_info &, format_result *);
> };
> 
> bool
>@@ -2357,7 +2357,7 @@ add_bytes (const pass_sprintf_length::ca
>    that caused the processing to be terminated early).  */
> 
> bool
>-pass_sprintf_length::compute_format_length (const call_info &info,
>+pass_sprintf_length::compute_format_length (call_info &info,
> 					    format_result *res)
> {
>   /* The variadic argument counter.  */
>@@ -2624,6 +2624,9 @@ pass_sprintf_length::compute_format_leng
> 	  return false;
> 
> 	case 'n':
>+	  /* %n has side-effects even when nothing is actually printed to
>+	     any buffer.  */
>+	  info.nowrite = false;
> 	  break;
> 
> 	case 'c':
>--- gcc/testsuite/gcc.dg/pr78965.c.jj	2017-01-02 12:12:15.959803429
>+0100
>+++ gcc/testsuite/gcc.dg/pr78965.c	2017-01-02 12:11:06.000000000 +0100
>@@ -0,0 +1,14 @@
>+/* PR tree-optimization/78965 */
>+/* { dg-do run { target c99_runtime } } */
>+/* { dg-options "-O2" } */
>+/* { dg-add-options c99_runtime } */
>+
>+int
>+main ()
>+{
>+  int a = 5, b = 6;
>+  int c = __builtin_snprintf (0, 0, "a%nb%nc", &a, &b);
>+  if (a + b + c != 6)
>+    __builtin_abort ();
>+  return 0;
>+}
>
>	Jakub
diff mbox

Patch

--- gcc/gimple-ssa-sprintf.c.jj	2017-01-01 12:45:35.000000000 +0100
+++ gcc/gimple-ssa-sprintf.c	2017-01-02 12:09:29.902945255 +0100
@@ -131,7 +131,7 @@  public:
   void handle_gimple_call (gimple_stmt_iterator*);
 
   struct call_info;
-  bool compute_format_length (const call_info &, format_result *);
+  bool compute_format_length (call_info &, format_result *);
 };
 
 bool
@@ -2357,7 +2357,7 @@  add_bytes (const pass_sprintf_length::ca
    that caused the processing to be terminated early).  */
 
 bool
-pass_sprintf_length::compute_format_length (const call_info &info,
+pass_sprintf_length::compute_format_length (call_info &info,
 					    format_result *res)
 {
   /* The variadic argument counter.  */
@@ -2624,6 +2624,9 @@  pass_sprintf_length::compute_format_leng
 	  return false;
 
 	case 'n':
+	  /* %n has side-effects even when nothing is actually printed to
+	     any buffer.  */
+	  info.nowrite = false;
 	  break;
 
 	case 'c':
--- gcc/testsuite/gcc.dg/pr78965.c.jj	2017-01-02 12:12:15.959803429 +0100
+++ gcc/testsuite/gcc.dg/pr78965.c	2017-01-02 12:11:06.000000000 +0100
@@ -0,0 +1,14 @@ 
+/* PR tree-optimization/78965 */
+/* { dg-do run { target c99_runtime } } */
+/* { dg-options "-O2" } */
+/* { dg-add-options c99_runtime } */
+
+int
+main ()
+{
+  int a = 5, b = 6;
+  int c = __builtin_snprintf (0, 0, "a%nb%nc", &a, &b);
+  if (a + b + c != 6)
+    __builtin_abort ();
+  return 0;
+}