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  <ja...@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


Reply via email to