diff options
| author | Paul Eggert | 2013-12-12 11:23:25 -0800 |
|---|---|---|
| committer | Paul Eggert | 2013-12-12 11:23:25 -0800 |
| commit | 4618713ae48aac51c6f1a2474cc981f32c2bbede (patch) | |
| tree | 11ede5202ee196ab2fb658a6c5a4bcffc4dc413b /src | |
| parent | 01633a17e74e638f31ec71c3587481f0084574f2 (diff) | |
| download | emacs-4618713ae48aac51c6f1a2474cc981f32c2bbede.tar.gz emacs-4618713ae48aac51c6f1a2474cc981f32c2bbede.zip | |
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.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 8 | ||||
| -rw-r--r-- | src/regex.c | 20 |
2 files changed, 17 insertions, 11 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 839630e93ea..7bbcb345a0f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,11 @@ | |||
| 1 | 2013-12-12 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Avoid undefined behavior with huge regexp interval counts. | ||
| 4 | * regex.c (GET_INTERVAL_COUNT): Rename from 'GET_UNSIGNED_NUMBER', | ||
| 5 | since it's now specialized to interval counts. All uses changed. | ||
| 6 | Do not assume wrapraound on signed integer overflow. | ||
| 7 | (regex_compile): Simplify based on the above changes. | ||
| 8 | |||
| 1 | 2013-12-12 Eli Zaretskii <eliz@gnu.org> | 9 | 2013-12-12 Eli Zaretskii <eliz@gnu.org> |
| 2 | 10 | ||
| 3 | Support file names on MS-Windows that use characters outside of | 11 | Support file names on MS-Windows that use characters outside of |
diff --git a/src/regex.c b/src/regex.c index b45dbcaada7..faa645cdd28 100644 --- a/src/regex.c +++ b/src/regex.c | |||
| @@ -1989,7 +1989,7 @@ struct range_table_work_area | |||
| 1989 | #endif /* emacs */ | 1989 | #endif /* emacs */ |
| 1990 | 1990 | ||
| 1991 | /* Get the next unsigned number in the uncompiled pattern. */ | 1991 | /* Get the next unsigned number in the uncompiled pattern. */ |
| 1992 | #define GET_UNSIGNED_NUMBER(num) \ | 1992 | #define GET_INTERVAL_COUNT(num) \ |
| 1993 | do { \ | 1993 | do { \ |
| 1994 | if (p == pend) \ | 1994 | if (p == pend) \ |
| 1995 | FREE_STACK_RETURN (REG_EBRACE); \ | 1995 | FREE_STACK_RETURN (REG_EBRACE); \ |
| @@ -1998,13 +1998,11 @@ struct range_table_work_area | |||
| 1998 | PATFETCH (c); \ | 1998 | PATFETCH (c); \ |
| 1999 | while ('0' <= c && c <= '9') \ | 1999 | while ('0' <= c && c <= '9') \ |
| 2000 | { \ | 2000 | { \ |
| 2001 | int prev; \ | ||
| 2002 | if (num < 0) \ | 2001 | if (num < 0) \ |
| 2003 | num = 0; \ | 2002 | num = 0; \ |
| 2004 | prev = num; \ | 2003 | if (RE_DUP_MAX / 10 - (RE_DUP_MAX % 10 < c - '0') < num) \ |
| 2005 | num = num * 10 + c - '0'; \ | ||
| 2006 | if (num / 10 != prev) \ | ||
| 2007 | FREE_STACK_RETURN (REG_BADBR); \ | 2004 | FREE_STACK_RETURN (REG_BADBR); \ |
| 2005 | num = num * 10 + c - '0'; \ | ||
| 2008 | if (p == pend) \ | 2006 | if (p == pend) \ |
| 2009 | FREE_STACK_RETURN (REG_EBRACE); \ | 2007 | FREE_STACK_RETURN (REG_EBRACE); \ |
| 2010 | PATFETCH (c); \ | 2008 | PATFETCH (c); \ |
| @@ -3310,18 +3308,18 @@ regex_compile (const_re_char *pattern, size_t size, reg_syntax_t syntax, | |||
| 3310 | 3308 | ||
| 3311 | beg_interval = p; | 3309 | beg_interval = p; |
| 3312 | 3310 | ||
| 3313 | GET_UNSIGNED_NUMBER (lower_bound); | 3311 | GET_INTERVAL_COUNT (lower_bound); |
| 3314 | 3312 | ||
| 3315 | if (c == ',') | 3313 | if (c == ',') |
| 3316 | GET_UNSIGNED_NUMBER (upper_bound); | 3314 | { |
| 3315 | GET_INTERVAL_COUNT (upper_bound); | ||
| 3316 | if (upper_bound < lower_bound) | ||
| 3317 | FREE_STACK_RETURN (REG_BADBR); | ||
| 3318 | } | ||
| 3317 | else | 3319 | else |
| 3318 | /* Interval such as `{1}' => match exactly once. */ | 3320 | /* Interval such as `{1}' => match exactly once. */ |
| 3319 | upper_bound = lower_bound; | 3321 | upper_bound = lower_bound; |
| 3320 | 3322 | ||
| 3321 | if (lower_bound < 0 || upper_bound > RE_DUP_MAX | ||
| 3322 | || (upper_bound >= 0 && lower_bound > upper_bound)) | ||
| 3323 | FREE_STACK_RETURN (REG_BADBR); | ||
| 3324 | |||
| 3325 | if (!(syntax & RE_NO_BK_BRACES)) | 3323 | if (!(syntax & RE_NO_BK_BRACES)) |
| 3326 | { | 3324 | { |
| 3327 | if (c != '\\') | 3325 | if (c != '\\') |