summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@gmail.com>2011-05-28 17:14:30 -0400
committerPetr Baudis <pasky@ucw.cz>2011-09-03 20:27:05 +0200
commit07c65bd7b3f8aaed2e6e567d4b1a932893e8838a (patch)
treecaaf99e51a1745f975fc0816c0e434fbc5a56d41
parent36edecaa99bfe160463da7df4b5810726be3eb53 (diff)
downloadglibc-07c65bd7b3f8aaed2e6e567d4b1a932893e8838a.tar.gz
Fix unnecessary overallocation due to incomplete character
When incomplete characters are found at the end of a string the code ran amok and allocated lots of memory. Stricter limits are now in place. (cherry picked from commit 8887a920a4b81a500f54893250085e0d1a52cf9a)
-rw-r--r--ChangeLog14
-rw-r--r--posix/Makefile2
-rw-r--r--posix/bug-regex32.c36
-rw-r--r--posix/regex_internal.c24
-rw-r--r--posix/regexec.c20
5 files changed, 76 insertions, 20 deletions
diff --git a/ChangeLog b/ChangeLog
index da84df385d..da762ca3a6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2011-05-28 Ulrich Drepper <drepper@gmail.com>
+
+ [BZ #12811]
+ * posix/regex_internal.c (build_wcs_buffer): Don't signal we have to
+ grow the buffers more if it already has to be sufficient.
+ (build_wcs_upper_buffer): Likewise.
+ * posix/regexec.c (check_matching): Likewise.
+ (clean_state_log_if_needed): Likewise.
+ (extend_buffers): Don't enlarge buffers beyond size of the input
+ buffer.
+ Patches mostly by Emil Wojak <emil@wojak.eu>.
+ * posix/bug-regex32.c: New file.
+ * posix/Makefile (tests): Add bug-regex32.
+
2011-05-14 Ulrich Drepper <drepper@gmail.com>
* iconv/loop.c (SINGLE) [STORE_REST]: Add input bytes to bytebuf before
diff --git a/posix/Makefile b/posix/Makefile
index 4c9ff85652..df8fc47ca9 100644
--- a/posix/Makefile
+++ b/posix/Makefile
@@ -82,7 +82,7 @@ tests := tstgetopt testfnm runtests runptests \
bug-regex17 bug-regex18 bug-regex19 bug-regex20 \
bug-regex21 bug-regex22 bug-regex23 bug-regex24 \
bug-regex25 bug-regex26 bug-regex27 bug-regex28 \
- bug-regex29 bug-regex30 bug-regex31 \
+ bug-regex29 bug-regex30 bug-regex31 bug-regex32 \
tst-nice tst-nanosleep tst-regex2 \
transbug tst-rxspencer tst-pcre tst-boost \
bug-ga1 tst-vfork1 tst-vfork2 tst-vfork3 tst-waitid \
diff --git a/posix/bug-regex32.c b/posix/bug-regex32.c
new file mode 100644
index 0000000000..525232c69b
--- /dev/null
+++ b/posix/bug-regex32.c
@@ -0,0 +1,36 @@
+// BZ 12811
+#include <regex.h>
+#include <stdio.h>
+#include <locale.h>
+
+static int
+do_test (void)
+{
+ char buf[1000];
+ regex_t preg;
+ if (setlocale (LC_CTYPE, "de_DE.UTF-8") == NULL)
+ {
+ puts ("setlocale failed");
+ return 1;
+ }
+
+ int e = regcomp (&preg, ".*ab", REG_ICASE);
+ if (e != 0)
+ {
+ regerror (e, &preg, buf, sizeof (buf));
+ printf ("regcomp = %d \"%s\"\n", e, buf);
+ return 1;
+ }
+
+ // Incomplete character at the end of the buffer
+ e = regexec (&preg, "aaaaaaaaaaaa\xc4", 0, NULL, 0);
+
+ regfree (&preg);
+ regerror (e, &preg, buf, sizeof (buf));
+ printf ("regexec = %d \"%s\"\n", e, buf);
+
+ return e != REG_NOMATCH;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/posix/regex_internal.c b/posix/regex_internal.c
index 09cffcf0d7..6e75f47373 100644
--- a/posix/regex_internal.c
+++ b/posix/regex_internal.c
@@ -237,13 +237,8 @@ build_wcs_buffer (re_string_t *pstr)
else
p = (const char *) pstr->raw_mbs + pstr->raw_mbs_idx + byte_idx;
mbclen = __mbrtowc (&wc, p, remain_len, &pstr->cur_state);
- if (BE (mbclen == (size_t) -2, 0))
- {
- /* The buffer doesn't have enough space, finish to build. */
- pstr->cur_state = prev_st;
- break;
- }
- else if (BE (mbclen == (size_t) -1 || mbclen == 0, 0))
+ if (BE (mbclen == (size_t) -1 || mbclen == 0
+ || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len), 0))
{
/* We treat these cases as a singlebyte character. */
mbclen = 1;
@@ -252,6 +247,12 @@ build_wcs_buffer (re_string_t *pstr)
wc = pstr->trans[wc];
pstr->cur_state = prev_st;
}
+ else if (BE (mbclen == (size_t) -2, 0))
+ {
+ /* The buffer doesn't have enough space, finish to build. */
+ pstr->cur_state = prev_st;
+ break;
+ }
/* Write wide character and padding. */
pstr->wcs[byte_idx++] = wc;
@@ -334,9 +335,11 @@ build_wcs_upper_buffer (re_string_t *pstr)
for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
pstr->wcs[byte_idx++] = WEOF;
}
- else if (mbclen == (size_t) -1 || mbclen == 0)
+ else if (mbclen == (size_t) -1 || mbclen == 0
+ || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len))
{
- /* It is an invalid character or '\0'. Just use the byte. */
+ /* It is an invalid character, an incomplete character
+ at the end of the string, or '\0'. Just use the byte. */
int ch = pstr->raw_mbs[pstr->raw_mbs_idx + byte_idx];
pstr->mbs[byte_idx] = ch;
/* And also cast it to wide char. */
@@ -449,7 +452,8 @@ build_wcs_upper_buffer (re_string_t *pstr)
for (remain_len = byte_idx + mbclen - 1; byte_idx < remain_len ;)
pstr->wcs[byte_idx++] = WEOF;
}
- else if (mbclen == (size_t) -1 || mbclen == 0)
+ else if (mbclen == (size_t) -1 || mbclen == 0
+ || (mbclen == (size_t) -2 && pstr->bufs_len >= pstr->len))
{
/* It is an invalid character or '\0'. Just use the byte. */
int ch = pstr->raw_mbs[pstr->raw_mbs_idx + src_idx];
diff --git a/posix/regexec.c b/posix/regexec.c
index 5019003c39..756682ee68 100644
--- a/posix/regexec.c
+++ b/posix/regexec.c
@@ -1,5 +1,5 @@
/* Extended regular expression matching and search library.
- Copyright (C) 2002, 2003, 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+ Copyright (C) 2002-2005,2007,2009,2010,2011 Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Isamu Hasegawa <isamu@yamato.ibm.com>.
@@ -1134,12 +1134,13 @@ check_matching (re_match_context_t *mctx, int fl_longest_match,
re_dfastate_t *old_state = cur_state;
int next_char_idx = re_string_cur_idx (&mctx->input) + 1;
- if (BE (next_char_idx >= mctx->input.bufs_len, 0)
- || (BE (next_char_idx >= mctx->input.valid_len, 0)
- && mctx->input.valid_len < mctx->input.len))
- {
- err = extend_buffers (mctx);
- if (BE (err != REG_NOERROR, 0))
+ if ((BE (next_char_idx >= mctx->input.bufs_len, 0)
+ && mctx->input.bufs_len < mctx->input.len)
+ || (BE (next_char_idx >= mctx->input.valid_len, 0)
+ && mctx->input.valid_len < mctx->input.len))
+ {
+ err = extend_buffers (mctx);
+ if (BE (err != REG_NOERROR, 0))
{
assert (err == REG_ESPACE);
return -2;
@@ -1710,7 +1711,8 @@ clean_state_log_if_needed (re_match_context_t *mctx, int next_state_log_idx)
{
int top = mctx->state_log_top;
- if (next_state_log_idx >= mctx->input.bufs_len
+ if ((next_state_log_idx >= mctx->input.bufs_len
+ && mctx->input.bufs_len < mctx->input.len)
|| (next_state_log_idx >= mctx->input.valid_len
&& mctx->input.valid_len < mctx->input.len))
{
@@ -4074,7 +4076,7 @@ extend_buffers (re_match_context_t *mctx)
re_string_t *pstr = &mctx->input;
/* Double the lengthes of the buffers. */
- ret = re_string_realloc_buffers (pstr, pstr->bufs_len * 2);
+ ret = re_string_realloc_buffers (pstr, MIN (pstr->len, pstr->bufs_len * 2));
if (BE (ret != REG_NOERROR, 0))
return ret;