[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