diff mbox series

[committed] diagnostics: fix ICE on fix-it hints on very long lines [PR99323]

Message ID 20210302204911.2526893-1-dmalcolm@redhat.com
State New
Headers show
Series [committed] diagnostics: fix ICE on fix-it hints on very long lines [PR99323] | expand

Commit Message

David Malcolm March 2, 2021, 8:49 p.m. UTC
PR c/99323 describes an ICE due to a failed assertion deep inside the
fix-it printing machinery, where the fix-it hints on one line have not
been properly sorted in layout's constructor.

The underlying issue occurs when multiple fix-it hints affect a line
wider that LINE_MAP_MAX_COLUMN_NUMBER, where the location_t values for
characters after that threshold fall back to having column zero.

It's not meaningful to try to handle fix-it hints without column
information, so this patch rejects them as they are added to the
rich_location, falling back to the "no fix-it hints on this diagnostic"
case, fixing the crash.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r11-7461-g41fbacdd10305654b1d10f887fa3f4677f9b8f34.

gcc/ChangeLog:
	PR c/99323
	* diagnostic-show-locus.c
	(selftest::test_one_liner_many_fixits_2): Fix accidental usage of
	column 0.

gcc/testsuite/ChangeLog:
	PR c/99323
	* gcc.dg/pr99323-1.c: New test.
	* gcc.dg/pr99323-2.c: New test.

libcpp/ChangeLog:
	PR c/99323
	* line-map.c (rich_location::maybe_add_fixit): Reject fix-it hints
	at column 0.
---
 gcc/diagnostic-show-locus.c      |  4 ++--
 gcc/testsuite/gcc.dg/pr99323-1.c | 17 +++++++++++++++++
 gcc/testsuite/gcc.dg/pr99323-2.c | 11 +++++++++++
 libcpp/line-map.c                |  8 ++++++++
 4 files changed, 38 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr99323-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr99323-2.c
diff mbox series

Patch

diff --git a/gcc/diagnostic-show-locus.c b/gcc/diagnostic-show-locus.c
index 458830aa2a9..4111cd66544 100644
--- a/gcc/diagnostic-show-locus.c
+++ b/gcc/diagnostic-show-locus.c
@@ -3288,14 +3288,14 @@  test_one_liner_many_fixits_2 ()
   rich_location richloc (line_table, equals);
   for (int i = 0; i < 19; i++)
     {
-      location_t loc = linemap_position_for_column (line_table, i * 2);
+      location_t loc = linemap_position_for_column (line_table, (i * 2) + 1);
       richloc.add_fixit_insert_before (loc, "a");
     }
   ASSERT_EQ (19, richloc.get_num_fixit_hints ());
   diagnostic_show_locus (&dc, &richloc, DK_ERROR);
   ASSERT_STREQ (" foo = bar.field;\n"
 		"     ^\n"
-		"a a a a a a a a a a a a a a a a a a a\n",
+		" a a a a a a a a a a a a a a a a a a a\n",
 		pp_formatted_text (dc.printer));
 }
 
diff --git a/gcc/testsuite/gcc.dg/pr99323-1.c b/gcc/testsuite/gcc.dg/pr99323-1.c
new file mode 100644
index 00000000000..6fe14002e59
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr99323-1.c
@@ -0,0 +1,17 @@ 
+/* Verify that fix-it printing doesn't ICE when there are multiple
+   fix-it hints on a very long line after LINE_MAP_MAX_COLUMN_NUMBER.  */
+
+/* { dg-options "-Wall -no-integrated-cpp -fdiagnostics-show-caret" } */
+/* { dg-allow-blank-lines-in-output 1 } */
+/* { dg-prune-output ".*" } */
+
+typedef struct {
+} REFERENCE;
+#define LIM2() LIM1()
+#define LIM3() LIM2() LIM2() LIM2() LIM2() LIM2() LIM2()
+#define LIM4()                                                                 \
+  LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3() LIM3()
+#define LIM5()                                                                 \
+  LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4() LIM4()
+#define LIM1() DEF(),
+REFERENCE references[] = {LIM5()};
diff --git a/gcc/testsuite/gcc.dg/pr99323-2.c b/gcc/testsuite/gcc.dg/pr99323-2.c
new file mode 100644
index 00000000000..d4075b61525
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr99323-2.c
@@ -0,0 +1,11 @@ 
+/* Verify that fix-it printing doesn't ICE when there are multiple
+   fix-it hints on a very long line after LINE_MAP_MAX_COLUMN_NUMBER.  */
+
+/* { dg-options "-Wall -fdiagnostics-show-caret" } */
+/* { dg-allow-blank-lines-in-output 1 } */
+/* { dg-prune-output ".*" } */
+
+typedef struct {
+} REFERENCE;
+
+REFERENCE references[] = {DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(), DEF(),}
diff --git a/libcpp/line-map.c b/libcpp/line-map.c
index ccabd51c62f..a003af8533c 100644
--- a/libcpp/line-map.c
+++ b/libcpp/line-map.c
@@ -2431,6 +2431,14 @@  rich_location::maybe_add_fixit (location_t start,
       stop_supporting_fixits ();
       return;
     }
+  /* If we have very long lines, tokens will eventually fall back to
+     having column == 0.
+     We can't handle fix-it hints that use such locations.  */
+  if (exploc_start.column == 0 || exploc_next_loc.column == 0)
+    {
+      stop_supporting_fixits ();
+      return;
+    }
 
   const char *newline = strchr (new_content, '\n');
   if (newline)