gcc.dg/tree-ssa/builtin-sprintf-2.c is showing intermittent failures, which
valgrind shows to be a read past the end of a buffer.

The root cause is that the on-demand substring loc code isn't set up
to cope with -ftrack-macro-expansion != 2 (the default).

In the failing case, it attempts to use this location as the location
of the literal:

../../src/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-2.c:95:1: note:
 RNG (0,  0,  0, "%hhi", i)
 ^~~

rather than:

 RNG (0,  0,  0, "%hhi", i)
                  ^~~~

On re-parsing to generate the on-demand substring locations, it thus
erroneously attempts to parse the 'R' as a raw string, and so this
code within cpp_interpret_string_1 fires:

      if (*p == 'R')
        {
          const uchar *prefix;

          /* Skip over 'R"'.  */
          p += 2;
          prefix = p;
          while (*p != '(')
            p++;

and the issue happens in the "while" loop, as it erroneously
walks through this memory:

(gdb) p strs.m_vec.m_vecdata[0]
$20 = {len = 3, text = 0xc9bcca0 "RNG"}

trying to find the open parenthesis, and starts reading beyond the
allocated buffer.

The fix is to require that -ftrack-macro-expansion == 2 (the default)
for on-demand string literal locations to be available, failing
gracefully to simply using the whole location_t otherwise.

Doing so requires some fixups to existing test cases:
[gcc.dg/tree-ssa/builtin-sprintf-warn-{1,4}.c both have
-ftrack-macro-expansion=0.  In the latter case, it seems to be
unnecessary, so this patch removes it.  In the former case, it
seems to be needed, but there are some expected locations in
test_sprintf_note that are changed by the patch.  It's not clear to
me how to fix that, so for now the patch removes the expected
column numbers from that function within the test case.

Successfully bootstrapped&regrtested on x86_64-pc-linux-gnu.

I think I can self-approve the input.c change and new test cases,
but I'm not sure about the changes to Martin's test cases.

Martin: are the changes to your test cases OK by you, or is there
a better way to rewrite them?

gcc/ChangeLog:
        PR preprocessor/78324
        * input.c (get_substring_ranges_for_loc): Fail gracefully if
        -ftrack-macro-expansion has a value other than 2.

gcc/testsuite/ChangeLog:
        PR preprocessor/78324
        * gcc.dg/plugin/diagnostic-test-string-literals-1.c
        (test_multitoken_macro): New function.
        * gcc.dg/plugin/diagnostic-test-string-literals-3.c: New test
        case.
        * gcc.dg/plugin/diagnostic-test-string-literals-4.c: New test
        case.
        * gcc.dg/plugin/plugin.exp (plugin_test_list): Add the new test
        cases.
        * gcc.dg/tree-ssa/builtin-sprintf-warn-1.c (test_sprintf_note):
        Drop expected column numbers from dg-warning directives.
        * gcc.dg/tree-ssa/builtin-sprintf-warn-4.c: Drop
        -ftrack-macro-expansion=0.
---
 gcc/input.c                                        |  9 +++++
 .../plugin/diagnostic-test-string-literals-1.c     | 16 ++++++++
 .../plugin/diagnostic-test-string-literals-3.c     | 43 ++++++++++++++++++++++
 .../plugin/diagnostic-test-string-literals-4.c     | 43 ++++++++++++++++++++++
 gcc/testsuite/gcc.dg/plugin/plugin.exp             |  4 +-
 .../gcc.dg/tree-ssa/builtin-sprintf-warn-1.c       |  6 +--
 .../gcc.dg/tree-ssa/builtin-sprintf-warn-4.c       |  2 +-
 7 files changed, 118 insertions(+), 5 deletions(-)
 create mode 100644 
gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-3.c
 create mode 100644 
gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-4.c

diff --git a/gcc/input.c b/gcc/input.c
index 728f4dd..611e18b 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -1322,6 +1322,15 @@ get_substring_ranges_for_loc (cpp_reader *pfile,
   if (strloc == UNKNOWN_LOCATION)
     return "unknown location";
 
+  /* Reparsing the strings requires accurate location information.
+     If -ftrack-macro-expansion has been overridden from its default
+     of 2, then we might have a location of a macro expansion point,
+     rather than the location of the literal itself.
+     Avoid this by requiring that we have full macro expansion tracking
+     for substring locations to be available.  */
+  if (cpp_get_options (pfile)->track_macro_expansion != 2)
+    return "track_macro_expansion != 2";
+
   /* If string concatenation has occurred at STRLOC, get the locations
      of all of the literal tokens making up the compound string.
      Otherwise, just use STRLOC.  */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c 
b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c
index 3e44936..76a085e 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-1.c
@@ -243,6 +243,22 @@ test_macro (void)
    { dg-end-multiline-output "" } */
 }
 
+void
+test_multitoken_macro (void)
+{
+#define RANGE ("0123456789")  /* { dg-error "unable to read substring 
location: macro expansion" } */
+  __emit_string_literal_range (RANGE, 4, 3, 6);
+/* { dg-begin-multiline-output "" }
+ #define RANGE ("0123456789")
+               ^
+   { dg-end-multiline-output "" } */
+/* { dg-begin-multiline-output "" }
+   __emit_string_literal_range (RANGE, 4, 3, 6);
+                                ^~~~~
+   { dg-end-multiline-output "" } */
+#undef RANGE
+}
+
 /* Verify that the location of the closing quote is used
    for the location of the null terminating character.  */
 
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-3.c 
b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-3.c
new file mode 100644
index 0000000..95b78bc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-3.c
@@ -0,0 +1,43 @@
+/* Similar to diagnostic-test-string-literals-1.c, but with
+   -ftrack-macro-expansion=0.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -ftrack-macro-expansion=0" } */
+
+extern void __emit_string_literal_range (const void *literal, int caret_idx,
+                                        int start_idx, int end_idx);
+
+void
+test_simple_string_literal (void)
+{
+  __emit_string_literal_range ("0123456789", /* { dg-error "unable to read 
substring location: track_macro_expansion != 2" } */
+                              6, 6, 7);
+}
+
+void
+test_concatenated_string_literal (void)
+{
+  __emit_string_literal_range ("01234" "56789", /* { dg-error "unable to read 
substring location: track_macro_expansion != 2" } */
+                              4, 3, 6);
+}
+
+/* To reproduce PR preprocessor/78324, the macro name should start
+   with the letter 'R'.  */
+
+void
+test_macro (void)
+{
+#define RANGE "01234"
+  __emit_string_literal_range (RANGE /* { dg-error "unable to read substring 
location: track_macro_expansion != 2" } */
+                               "56789",
+                               4, 3, 6);
+#undef RANGE
+}
+
+void
+test_multitoken_macro (void)
+{
+#define RANGE ("0123456789")
+  __emit_string_literal_range (RANGE, 4, 3, 6); /* { dg-error "unable to read 
substring location: track_macro_expansion != 2" } */
+#undef RANGE
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-4.c 
b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-4.c
new file mode 100644
index 0000000..d47818a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-4.c
@@ -0,0 +1,43 @@
+/* Similar to diagnostic-test-string-literals-1.c, but with
+   -ftrack-macro-expansion=1.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -ftrack-macro-expansion=1" } */
+
+extern void __emit_string_literal_range (const void *literal, int caret_idx,
+                                        int start_idx, int end_idx);
+
+void
+test_simple_string_literal (void)
+{
+  __emit_string_literal_range ("0123456789", /* { dg-error "unable to read 
substring location: track_macro_expansion != 2" } */
+                              6, 6, 7);
+}
+
+void
+test_concatenated_string_literal (void)
+{
+  __emit_string_literal_range ("01234" "56789", /* { dg-error "unable to read 
substring location: track_macro_expansion != 2" } */
+                              4, 3, 6);
+}
+
+/* To reproduce PR preprocessor/78324, the macro name should start
+   with the letter 'R'.  */
+
+void
+test_macro (void)
+{
+#define RANGE "01234"  /* { dg-error "unable to read substring location: 
track_macro_expansion != 2" } */
+  __emit_string_literal_range (RANGE
+                               "56789",
+                               4, 3, 6);
+#undef RANGE
+}
+
+void
+test_multitoken_macro (void)
+{
+#define RANGE ("0123456789")  /* { dg-error "unable to read substring 
location: track_macro_expansion != 2" } */
+  __emit_string_literal_range (RANGE, 4, 3, 6);
+#undef RANGE
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp 
b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index 32ca748..eb15a66 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -73,7 +73,9 @@ set plugin_test_list [list \
          diagnostic-test-show-trees-1.c } \
     { diagnostic_plugin_test_string_literals.c \
          diagnostic-test-string-literals-1.c \
-         diagnostic-test-string-literals-2.c } \
+         diagnostic-test-string-literals-2.c \
+         diagnostic-test-string-literals-3.c \
+         diagnostic-test-string-literals-4.c } \
     { location_overflow_plugin.c \
          location-overflow-test-1.c \
          location-overflow-test-2.c } \
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c 
b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
index 5779a95..b6a6011 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-1.c
@@ -181,13 +181,13 @@ void test_sprintf_note (void)
   /* Diagnostic column numbers are 1-based.  */
 
   P (buffer (0),                /* { dg-message "format output 4 bytes into a 
destination of size 0" } */
-     "%c%s%i", '1', "2", 3);    /* { dg-warning "7:.%c. directive writing 1 
byte into a region of size 0" } */
+     "%c%s%i", '1', "2", 3);    /* { dg-warning ".%c. directive writing 1 byte 
into a region of size 0" } */
 
   P (buffer (1),                /* { dg-message "format output 6 bytes into a 
destination of size 1" } */
-     "%c%s%i", '1', "23", 45);  /* { dg-warning "9:.%s. directive writing 2 
bytes into a region of size 0" } */
+     "%c%s%i", '1', "23", 45);  /* { dg-warning ".%s. directive writing 2 
bytes into a region of size 0" } */
 
   P (buffer (2),                /* { dg-message "format output 6 bytes into a 
destination of size 2" } */
-     "%c%s%i", '1', "2", 345);  /* { dg-warning "11:.%i. directive writing 3 
bytes into a region of size 0" } */
+     "%c%s%i", '1', "2", 345);  /* { dg-warning ".%i. directive writing 3 
bytes into a region of size 0" } */
 
   /* It would be nice if the caret in the location range for the format
      string below could be made to point at the closing quote of the format
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-4.c 
b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-4.c
index faa5806..b587d00 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-4.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/builtin-sprintf-warn-4.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-Wformat -Wformat-length=1 -fdiagnostics-show-caret 
-ftrack-macro-expansion=0" } */
+/* { dg-options "-Wformat -Wformat-length=1 -fdiagnostics-show-caret" } */
 
 extern int sprintf (char*, const char*, ...);
 
-- 
1.8.5.3

Reply via email to