[gcc r11-7511] c-ppoutput: Fix preprocessing ICE on very large line number [PR99325]

Jakub Jelinek jakub@gcc.gnu.org
Thu Mar 4 15:03:02 GMT 2021


https://gcc.gnu.org/g:a1b56c3ef70036af6d171d61ea48ad4c368fcb5b

commit r11-7511-ga1b56c3ef70036af6d171d61ea48ad4c368fcb5b
Author: Jakub Jelinek <jakub@redhat.com>
Date:   Thu Mar 4 16:02:07 2021 +0100

    c-ppoutput: Fix preprocessing ICE on very large line number [PR99325]
    
    In libcpp, lines are represented as linenum_type, which is unsigned int.
    The following testcases ICE because maybe_print_line_1 is sometimes called
    with UNKNOWN_LOCATION (e.g. at pragma eof) and while most of the time
    the
            && src_line >= print.src_line
            && src_line < print.src_line + 8
    check doesn't succeed for the src_line of 0 from UNKNOWN_LOCATION, when
    print.src_line is from very large line numbers (UINT_MAX - 7 and above)
    it succeeds (with UB on the compiler side) but src_file is NULL for
    UNKNOWN_LOCATION and so the strcmp call ICEs.
    As print.src_line can easily wrap around, this patch changes its type
    to unsigned int to match libcpp, so that we don't invoke UB in the compiler.
    For print.src_line of UINT_MAX - 7 and above, src_line from UNKNOWN_LOCATION
    will not pass that test anymore, but when it wraps around to 0, it can,
    so I've also added a check for src_loc != UNKNOWN_LOCATION (or, if
    preferred, could be src_file != NULL).
    Besides fixing the ICE and UB in the compiler, I believe worst case the
    patch will cause printing a few more line directives in the preprocessed
    source around the wrapping from lines UINT_MAX - 7 to 0 (but less
    around the wrapping from INT_MAX to INT_MAX + 1U), but I think those
    are exceptional cases (sources with > 2billion lines are rare and
    we warn or error on #line > INT_MAX).
    
    2021-03-04  Jakub Jelinek  <jakub@redhat.com>
    
            PR c/99325
            * c-ppoutput.c (print): Change src_line type from int to unsigned.
            (token_streamer::stream) Likewise.
            (maybe_print_line_1): Likewise.  Don't strcmp src_file if src_loc is
            UNKNOWN_LOCATION.
    
            * gcc.dg/cpp/line11.c: New test.
            * gcc.dg/cpp/line12.c: New test.

Diff:
---
 gcc/c-family/c-ppoutput.c         | 9 +++++----
 gcc/testsuite/gcc.dg/cpp/line11.c | 6 ++++++
 gcc/testsuite/gcc.dg/cpp/line12.c | 6 ++++++
 3 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/gcc/c-family/c-ppoutput.c b/gcc/c-family/c-ppoutput.c
index 04e41645e81..ae33c1ff40f 100644
--- a/gcc/c-family/c-ppoutput.c
+++ b/gcc/c-family/c-ppoutput.c
@@ -32,7 +32,7 @@ static struct
   FILE *outf;			/* Stream to write to.  */
   const cpp_token *prev;	/* Previous token.  */
   const cpp_token *source;	/* Source token for spacing.  */
-  int src_line;			/* Line number currently being written.  */
+  unsigned src_line;		/* Line number currently being written.  */
   bool printed;			/* True if something output at line.  */
   bool first_time;		/* pp_file_change hasn't been called yet.  */
   bool prev_was_system_token;	/* True if the previous token was a
@@ -213,7 +213,7 @@ token_streamer::stream (cpp_reader *pfile, const cpp_token *token,
   /* Subtle logic to output a space if and only if necessary.  */
   if (avoid_paste)
     {
-      int src_line = LOCATION_LINE (loc);
+      unsigned src_line = LOCATION_LINE (loc);
 
       if (print.source == NULL)
 	print.source = token;
@@ -237,7 +237,7 @@ token_streamer::stream (cpp_reader *pfile, const cpp_token *token,
     }
   else if (token->flags & PREV_WHITE)
     {
-      int src_line = LOCATION_LINE (loc);
+      unsigned src_line = LOCATION_LINE (loc);
 
       if (src_line != print.src_line
 	  && do_line_adjustments
@@ -437,7 +437,7 @@ static bool
 maybe_print_line_1 (location_t src_loc, FILE *stream)
 {
   bool emitted_line_marker = false;
-  int src_line = LOCATION_LINE (src_loc);
+  unsigned src_line = LOCATION_LINE (src_loc);
   const char *src_file = LOCATION_FILE (src_loc);
 
   /* End the previous line of text.  */
@@ -451,6 +451,7 @@ maybe_print_line_1 (location_t src_loc, FILE *stream)
   if (!flag_no_line_commands
       && src_line >= print.src_line
       && src_line < print.src_line + 8
+      && src_loc != UNKNOWN_LOCATION
       && strcmp (src_file, print.src_file) == 0)
     {
       while (src_line > print.src_line)
diff --git a/gcc/testsuite/gcc.dg/cpp/line11.c b/gcc/testsuite/gcc.dg/cpp/line11.c
new file mode 100644
index 00000000000..67c6583f7da
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/line11.c
@@ -0,0 +1,6 @@
+/* PR c/99325 */
+/* { dg-do preprocess } */
+/* { dg-options "-pedantic" } */
+
+#line 4294967295	/* { dg-warning "line number out of range" } */
+#pragma message "foo"
diff --git a/gcc/testsuite/gcc.dg/cpp/line12.c b/gcc/testsuite/gcc.dg/cpp/line12.c
new file mode 100644
index 00000000000..c2e88f67bf9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/line12.c
@@ -0,0 +1,6 @@
+/* PR c/99325 */
+/* { dg-do preprocess } */
+/* { dg-options "-pedantic" } */
+
+#line 9223372036854775807	/* { dg-warning "line number out of range" } */
+#pragma message "foo"


More information about the Gcc-cvs mailing list