diff mbox

[committed] Prevent ICEs due to bogus substring locations (PR preprocessor/79210)

Message ID 1485896328-29281-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm Jan. 31, 2017, 8:58 p.m. UTC
PR preprocessor/79210 identifies a ICE due to a failing assertion
within get_substring_ranges_for_loc when re-lexing strings, due to
the wrong location being used for a string token.

The root cause of the bogus string location is due to
(A) a bogus location being generated when pasting together two tokens
during macro expansion.  This bogus location gets inherited by
subsequent temporary tokens during the expansion, including
(B) that of a stringized macro argument - the
assertion failure happens when attempting to re-lex the string token
obtained from this stringized macro argument, used within a string
concatenation.

It doesn't appear possible to give (A) a full
source_location/location_t since such a value can only cover one range
(rather than the multiple ranges involved in pasted tokens).

The location of (B) could perhaps be addressed by giving the stringized
token the location of the macro argument.  However, this would not
address the issue with re-lexing the string, which expects C/C++ syntax
(quotes, etc).

So the simplest fix at stage 4 is to convert the assertion into an
error-checking conditional, so that when this situation occurs, we
don't provide a location_t within the string, and instead fail
gracefully by providing the location for the start of the string.

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

Committed to trunk as r245070.

gcc/ChangeLog:
	PR preprocessor/79210
	* input.c (get_substring_ranges_for_loc): Replace line_width
	assertion with error-handling.

gcc/testsuite/ChangeLog:
	PR preprocessor/79210
	* gcc.dg/format/pr79210.c: New test case.
	* gcc.dg/plugin/diagnostic-test-string-literals-2.c (test_pr79210):
	New function.
---
 gcc/input.c                                        |  5 ++++-
 gcc/testsuite/gcc.dg/format/pr79210.c              | 23 ++++++++++++++++++++++
 .../plugin/diagnostic-test-string-literals-2.c     | 23 ++++++++++++++++++++++
 3 files changed, 50 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.dg/format/pr79210.c
diff mbox

Patch

diff --git a/gcc/input.c b/gcc/input.c
index 3e67314..38deb62 100644
--- a/gcc/input.c
+++ b/gcc/input.c
@@ -1395,7 +1395,10 @@  get_substring_ranges_for_loc (cpp_reader *pfile,
       const char *literal = line + start.column - 1;
       int literal_length = finish.column - start.column + 1;
 
-      gcc_assert (line_width >= (start.column - 1 + literal_length));
+      /* Ensure that we don't crash if we got the wrong location.  */
+      if (line_width < (start.column - 1 + literal_length))
+	return "line is not wide enough";
+
       cpp_string from;
       from.len = literal_length;
       /* Make a copy of the literal, to avoid having to rely on
diff --git a/gcc/testsuite/gcc.dg/format/pr79210.c b/gcc/testsuite/gcc.dg/format/pr79210.c
new file mode 100644
index 0000000..71f5dd6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/format/pr79210.c
@@ -0,0 +1,23 @@ 
+/* { dg-do compile } */
+/* { dg-options "-Wformat -Wformat-signedness" } */
+
+__attribute__((format(printf, 3, 4)))
+void dev_printk(const char *level, void *dev, const char *fmt, ...);
+
+#define lpfc_vport_param_init(attr)	\
+void lpfc_##attr##_init(void *vport, unsigned int val) \
+{ \
+	dev_printk("3", (void *)0, \
+		   "0423 lpfc_"#attr" attribute cannot be set to %d, "\
+		   "allowed range is [0, 1]\n", val); \
+}
+
+#define LPFC_VPORT_ATTR_R(name, desc) \
+unsigned int lpfc_##name;\
+lpfc_vport_param_init(name)\
+
+LPFC_VPORT_ATTR_R(peer_port_login,
+		  "Allow peer ports on the same physical port to login to each "
+		  "other.");
+
+/* { dg-warning "6: format .%d. expects argument of type .int., but argument 4 has type .unsigned int. " "" { target *-*-* } .-12 } */
diff --git a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c
index 25cb3f0..e916b93 100644
--- a/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c
+++ b/gcc/testsuite/gcc.dg/plugin/diagnostic-test-string-literals-2.c
@@ -51,3 +51,26 @@  test_stringified_token_3 (int x)
 #undef FOO
 }
 
+/* Test of a stringified macro argument within a concatenation.  */
+
+void
+test_pr79210 (void)
+{
+#define lpfc_vport_param_init(attr)    \
+       __emit_string_literal_range ( \
+                  "0423 lpfc_"#attr" attribute cannot be set to %d, "\
+                  "allowed range is [0, 1]\n", 54, 53, 54) \
+
+#define LPFC_VPORT_ATTR_R(name, decc)		\
+  unsigned int lpfc_##name;			\
+  lpfc_vport_param_init(name) \
+
+  LPFC_VPORT_ATTR_R(peer_port_login,
+  "some multiline blurb with a short final line "
+  "here");
+
+  /* { dg-error "19: unable to read substring location: line is not wide enough" "" { target *-*-* } .-11 } */
+
+#undef LPFC_VPORT_ATTR_R
+#undef lpfc_vport_param_init
+}