]> granicus.if.org Git - php/commitdiff
Fixed bug #76319
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 25 May 2018 09:33:13 +0000 (11:33 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 25 May 2018 09:33:13 +0000 (11:33 +0200)
While at it, also make sure that mbstring case conversion takes
into account the specified substitution character and substitution
mode.

NEWS
ext/mbstring/mbstring.c
ext/mbstring/php_unicode.c
ext/mbstring/php_unicode.h
ext/mbstring/tests/bug76319.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index f6fbad2b87c6a23ffbad79969628ab2aecb51339..b65ff55fd4c1b1e840abb6112adf091ed04387c1 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -105,6 +105,8 @@ PHP                                                                        NEWS
   . Fixed bug #73528 (Crash in zif_mb_send_mail). (Nikita)
   . Fixed bug #74929 (mbstring functions version 7.1.1 are slow compared to 5.3
     on Windows). (Nikita)
+  . Fixed bug #76319 (mb_strtolower with invalid UTF-8 causes segmentation
+    fault). (Nikita)
   . Update to Oniguruma 6.8.1. (cmb)
 
 - ODBC:
index 5f11a510aaba4cebb53e059caba690902e6708c4..171430f778742792a694041a0baf2a4dfae5f85e 100644 (file)
@@ -3252,6 +3252,14 @@ PHP_FUNCTION(mb_convert_encoding)
 }
 /* }}} */
 
+static char *mbstring_convert_case(
+               int case_mode, const char *str, size_t str_len, size_t *ret_len,
+               const mbfl_encoding *enc) {
+       return php_unicode_convert_case(
+               case_mode, str, str_len, ret_len, enc,
+               MBSTRG(current_filter_illegal_mode), MBSTRG(current_filter_illegal_substchar));
+}
+
 /* {{{ proto string mb_convert_case(string sourcestring, int mode [, string encoding])
    Returns a case-folded version of sourcestring */
 PHP_FUNCTION(mb_convert_case)
@@ -3280,7 +3288,7 @@ PHP_FUNCTION(mb_convert_case)
                return;
        }
 
-       newstr = php_unicode_convert_case(case_mode, str, str_len, &ret_len, enc);
+       newstr = mbstring_convert_case(case_mode, str, str_len, &ret_len, enc);
 
        if (newstr) {
                // TODO: avoid reallocation ???
@@ -3312,7 +3320,7 @@ PHP_FUNCTION(mb_strtoupper)
                RETURN_FALSE;
        }
 
-       newstr = php_unicode_convert_case(PHP_UNICODE_CASE_UPPER, str, str_len, &ret_len, enc);
+       newstr = mbstring_convert_case(PHP_UNICODE_CASE_UPPER, str, str_len, &ret_len, enc);
 
        if (newstr) {
                // TODO: avoid reallocation ???
@@ -3346,7 +3354,7 @@ PHP_FUNCTION(mb_strtolower)
                RETURN_FALSE;
        }
 
-       newstr = php_unicode_convert_case(PHP_UNICODE_CASE_LOWER, str, str_len, &ret_len, enc);
+       newstr = mbstring_convert_case(PHP_UNICODE_CASE_LOWER, str, str_len, &ret_len, enc);
 
        if (newstr) {
                // TODO: avoid reallocation ???
@@ -5172,7 +5180,7 @@ MBSTRING_API size_t php_mb_stripos(int mode, const char *old_haystack, size_t ol
                 * offsets otherwise. */
 
                size_t len = 0;
-               haystack.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, (char *)old_haystack, old_haystack_len, &len, enc);
+               haystack.val = (unsigned char *)mbstring_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, (char *)old_haystack, old_haystack_len, &len, enc);
                haystack.len = len;
 
                if (!haystack.val) {
@@ -5183,7 +5191,7 @@ MBSTRING_API size_t php_mb_stripos(int mode, const char *old_haystack, size_t ol
                        break;
                }
 
-               needle.val = (unsigned char *)php_unicode_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, (char *)old_needle, old_needle_len, &len, enc);
+               needle.val = (unsigned char *)mbstring_convert_case(PHP_UNICODE_CASE_FOLD_SIMPLE, (char *)old_needle, old_needle_len, &len, enc);
                needle.len = len;
 
                if (!needle.val) {
index 0cffec652e6e85f0c50555b4fc64ff35289f0a7b..ac452b6a20776189432823f23ddbecf809e65ebc 100644 (file)
@@ -312,6 +312,14 @@ static int convert_case_filter(int c, void *void_data)
        struct convert_case_data *data = (struct convert_case_data *) void_data;
        unsigned out[3];
        unsigned len, i;
+
+       /* Handle invalid characters early, as we assign special meaning to
+        * codepoints above 0xffffff. */
+       if (UNEXPECTED(c > 0xffffff)) {
+               (*data->next_filter->filter_function)(c, data->next_filter);
+               return 0;
+       }
+
        switch (data->case_mode) {
                case PHP_UNICODE_CASE_UPPER_SIMPLE:
                        out[0] = php_unicode_toupper_simple(c, data->no_encoding);
@@ -376,7 +384,7 @@ static int convert_case_filter(int c, void *void_data)
 
 MBSTRING_API char *php_unicode_convert_case(
                int case_mode, const char *srcstr, size_t srclen, size_t *ret_len,
-               const mbfl_encoding *src_encoding)
+               const mbfl_encoding *src_encoding, int illegal_mode, int illegal_substchar)
 {
        struct convert_case_data data;
        mbfl_convert_filter *from_wchar, *to_wchar;
@@ -403,6 +411,11 @@ MBSTRING_API char *php_unicode_convert_case(
                return NULL;
        }
 
+       to_wchar->illegal_mode = illegal_mode;
+       to_wchar->illegal_substchar = illegal_substchar;
+       from_wchar->illegal_mode = illegal_mode;
+       from_wchar->illegal_substchar = illegal_substchar;
+
        data.next_filter = from_wchar;
        data.no_encoding = src_encoding->no_encoding;
        data.case_mode = case_mode;
index 8868176fa1b0909c402d46e440140dd608028b03..68dff61da446cd63e6c237b93d046f926c0e854b 100644 (file)
@@ -87,8 +87,8 @@ MBSTRING_API int php_unicode_is_prop(unsigned long code, ...);
 MBSTRING_API int php_unicode_is_prop1(unsigned long code, int prop);
 
 MBSTRING_API char *php_unicode_convert_case(
-               int case_mode, const char *srcstr, size_t srclen, size_t *retlen,
-               const mbfl_encoding *src_encoding);
+               int case_mode, const char *srcstr, size_t srclen, size_t *ret_len,
+               const mbfl_encoding *src_encoding, int illegal_mode, int illegal_substchar);
 
 #define PHP_UNICODE_CASE_UPPER        0
 #define PHP_UNICODE_CASE_LOWER        1
diff --git a/ext/mbstring/tests/bug76319.phpt b/ext/mbstring/tests/bug76319.phpt
new file mode 100644 (file)
index 0000000..8b70602
--- /dev/null
@@ -0,0 +1,9 @@
+--TEST--
+Bug #76319: mb_strtolower with invalid UTF-8 causes segmentation fault
+--FILE--
+<?php
+mb_substitute_character(0xFFFD);
+var_dump(mb_strtolower("a\xA1", 'UTF-8'));
+?>
+--EXPECT--
+string(4) "a�"