From 4618713ae48aac51c6f1a2474cc981f32c2bbede Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Thu, 12 Dec 2013 11:23:25 -0800 Subject: [PATCH] Avoid undefined behavior with huge regexp interval counts. * regex.c (GET_INTERVAL_COUNT): Rename from 'GET_UNSIGNED_NUMBER', since it's now specialized to interval counts. All uses changed. Do not assume wrapraound on signed integer overflow. (regex_compile): Simplify based on the above changes. --- src/ChangeLog | 8 ++++++++ src/regex.c | 20 +++++++++----------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 839630e93e..7bbcb345a0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2013-12-12 Paul Eggert + + Avoid undefined behavior with huge regexp interval counts. + * regex.c (GET_INTERVAL_COUNT): Rename from 'GET_UNSIGNED_NUMBER', + since it's now specialized to interval counts. All uses changed. + Do not assume wrapraound on signed integer overflow. + (regex_compile): Simplify based on the above changes. + 2013-12-12 Eli Zaretskii Support file names on MS-Windows that use characters outside of diff --git a/src/regex.c b/src/regex.c index b45dbcaada..faa645cdd2 100644 --- a/src/regex.c +++ b/src/regex.c @@ -1989,7 +1989,7 @@ struct range_table_work_area #endif /* emacs */ /* Get the next unsigned number in the uncompiled pattern. */ -#define GET_UNSIGNED_NUMBER(num) \ +#define GET_INTERVAL_COUNT(num) \ do { \ if (p == pend) \ FREE_STACK_RETURN (REG_EBRACE); \ @@ -1998,13 +1998,11 @@ struct range_table_work_area PATFETCH (c); \ while ('0' <= c && c <= '9') \ { \ - int prev; \ if (num < 0) \ num = 0; \ - prev = num; \ - num = num * 10 + c - '0'; \ - if (num / 10 != prev) \ + if (RE_DUP_MAX / 10 - (RE_DUP_MAX % 10 < c - '0') < num) \ FREE_STACK_RETURN (REG_BADBR); \ + num = num * 10 + c - '0'; \ if (p == pend) \ FREE_STACK_RETURN (REG_EBRACE); \ PATFETCH (c); \ @@ -3310,18 +3308,18 @@ regex_compile (const_re_char *pattern, size_t size, reg_syntax_t syntax, beg_interval = p; - GET_UNSIGNED_NUMBER (lower_bound); + GET_INTERVAL_COUNT (lower_bound); if (c == ',') - GET_UNSIGNED_NUMBER (upper_bound); + { + GET_INTERVAL_COUNT (upper_bound); + if (upper_bound < lower_bound) + FREE_STACK_RETURN (REG_BADBR); + } else /* Interval such as `{1}' => match exactly once. */ upper_bound = lower_bound; - if (lower_bound < 0 || upper_bound > RE_DUP_MAX - || (upper_bound >= 0 && lower_bound > upper_bound)) - FREE_STACK_RETURN (REG_BADBR); - if (!(syntax & RE_NO_BK_BRACES)) { if (c != '\\') -- 2.20.1