aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2020-11-27 22:40:01 +0000
committerJoseph Myers <joseph@codesourcery.com>2020-11-27 22:40:01 +0000
commit9ccffd1298b5235b25ad05b89e3104fb2935fe27 (patch)
treecf825ab7f1747bd8cc89e4583b7e8585ddc2b0ea
parent5dbab7b3f4d3a8298aeb8ecde1cfbc4b16913d28 (diff)
downloadgcc-9ccffd1298b5235b25ad05b89e3104fb2935fe27.zip
gcc-9ccffd1298b5235b25ad05b89e3104fb2935fe27.tar.gz
gcc-9ccffd1298b5235b25ad05b89e3104fb2935fe27.tar.bz2
preprocessor: Fix #line overflow check [PR97602]
The preprocessor check for overflow (of linenum_type = unsigned int) when reading the line number in a #line directive is incomplete; it checks "reg < reg_prev" which doesn't cover all cases where multiplying by 10 overflowed. Fix this by checking for overflow before rather than after it occurs (using essentially the same logic as used by e.g. glibc printf when reading width and precision values from strings). Bootstrapped with no regressions for x86_64-pc-linux-gnu. libcpp/ 2020-11-27 Joseph Myers <joseph@codesourcery.com> PR preprocessor/97602 * directives.c (strtolinenum): Check for overflow before it occurs. Correct comment. gcc/testsuite/ 2020-11-27 Joseph Myers <joseph@codesourcery.com> PR preprocessor/97602 * gcc.dg/cpp/line9.c, gcc.dg/cpp/line10.c: New tests.
-rw-r--r--gcc/testsuite/gcc.dg/cpp/line10.c5
-rw-r--r--gcc/testsuite/gcc.dg/cpp/line9.c5
-rw-r--r--libcpp/directives.c10
3 files changed, 15 insertions, 5 deletions
diff --git a/gcc/testsuite/gcc.dg/cpp/line10.c b/gcc/testsuite/gcc.dg/cpp/line10.c
new file mode 100644
index 0000000..9f5f079
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/line10.c
@@ -0,0 +1,5 @@
+/* Test #line overflow checks: bug 97602. */
+/* { dg-do preprocess } */
+/* { dg-options "-pedantic" } */
+
+#line 4294967296 /* { dg-warning "line number out of range" } */
diff --git a/gcc/testsuite/gcc.dg/cpp/line9.c b/gcc/testsuite/gcc.dg/cpp/line9.c
new file mode 100644
index 0000000..8060aff
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cpp/line9.c
@@ -0,0 +1,5 @@
+/* Test #line overflow checks: bug 97602. */
+/* { dg-do preprocess } */
+/* { dg-options "-pedantic" } */
+
+#line 5000000000 /* { dg-warning "line number out of range" } */
diff --git a/libcpp/directives.c b/libcpp/directives.c
index fa66b5c..7511560 100644
--- a/libcpp/directives.c
+++ b/libcpp/directives.c
@@ -915,12 +915,11 @@ read_flag (cpp_reader *pfile, unsigned int last)
/* Subroutine of do_line and do_linemarker. Convert a number in STR,
of length LEN, to binary; store it in NUMP, and return false if the
number was well-formed, true if not. WRAPPED is set to true if the
- number did not fit into 'unsigned long'. */
+ number did not fit into 'linenum_type'. */
static bool
strtolinenum (const uchar *str, size_t len, linenum_type *nump, bool *wrapped)
{
linenum_type reg = 0;
- linenum_type reg_prev = 0;
uchar c;
*wrapped = false;
@@ -929,11 +928,12 @@ strtolinenum (const uchar *str, size_t len, linenum_type *nump, bool *wrapped)
c = *str++;
if (!ISDIGIT (c))
return true;
+ if (reg > ((linenum_type) -1) / 10)
+ *wrapped = true;
reg *= 10;
- reg += c - '0';
- if (reg < reg_prev)
+ if (reg > ((linenum_type) -1) - (c - '0'))
*wrapped = true;
- reg_prev = reg;
+ reg += c - '0';
}
*nump = reg;
return false;