]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Fix unnecessary overallocation due to incomplete character
authorUlrich Drepper <drepper@gmail.com>
Sat, 28 May 2011 21:14:30 +0000 (17:14 -0400)
committerPetr Baudis <pasky@ucw.cz>
Sat, 3 Sep 2011 18:27:05 +0000 (20:27 +0200)
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)

ChangeLog
posix/Makefile
posix/bug-regex32.c [new file with mode: 0644]
posix/regex_internal.c
posix/regexec.c

index da84df385d6d792703566e240c10cc86828e9ad8..da762ca3a6a65e7081ae15087528abf9816bd07e 100644 (file)
--- 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
index 4c9ff85652b109291caab5f5a3c8bbab9a8fe196..df8fc47ca940c64a6e08001494c91d916963edaa 100644 (file)
@@ -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 (file)
index 0000000..525232c
--- /dev/null
@@ -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"
index 09cffcf0d7b195117318f1da76a5e1e8d6982ece..6e75f47373c8bada777a039483001542dccb7610 100644 (file)
@@ -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];
index 5019003c39a03127123011d6983df5acd96b42c1..756682ee6827bad58a65a5ba736349dcc2b01100 100644 (file)
@@ -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;