]> granicus.if.org Git - php/commitdiff
Move offset error checking into mbfl_strpos
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 24 Jan 2020 09:29:34 +0000 (10:29 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 24 Jan 2020 09:50:02 +0000 (10:50 +0100)
This avoids calculating the full length only in order to validate
the offset, as mbfl_strpos needs to find the offset internally
anyway.

ext/mbstring/libmbfl/mbfl/mbfilter.c
ext/mbstring/mbstring.c
ext/mbstring/tests/bug43841.phpt
ext/mbstring/tests/bug45923.phpt
ext/mbstring/tests/mb_strpos_offset_errors.phpt [new file with mode: 0644]
ext/mbstring/tests/mb_strrpos_empty_needle.phpt

index 58f17db46d9b74bb290cb9b6e78fb8a8fe007cb3..3a3de216f3728c9726fb4b459d543b364fdbc840 100644 (file)
@@ -809,6 +809,37 @@ mbfl_oddlen(mbfl_string *string)
        /* NOT REACHED */
 }
 
+static const unsigned char *mbfl_find_offset_utf8(const mbfl_string *str, ssize_t offset) {
+       if (offset < 0) {
+               const unsigned char *pos = str->val + str->len;
+               const unsigned char *begin = str->val;
+               while (offset < 0) {
+                       if (pos <= begin) {
+                               return NULL;
+                       }
+
+                       unsigned char c = *(--pos);
+                       if (c < 0x80) {
+                               ++offset;
+                       } else if ((c & 0xc0) != 0x80) {
+                               ++offset;
+                       }
+               }
+               return pos;
+       } else {
+               const unsigned char *u8_tbl = mbfl_encoding_utf8.mblen_table;
+               const unsigned char *pos = str->val;
+               const unsigned char *end = str->val + str->len;
+               while (offset-- > 0) {
+                       if (pos >= end) {
+                               return NULL;
+                       }
+                       pos += u8_tbl[*pos];
+               }
+               return pos;
+       }
+}
+
 size_t
 mbfl_strpos(
     mbfl_string *haystack,
@@ -819,7 +850,7 @@ mbfl_strpos(
        size_t result;
        mbfl_string _haystack_u8, _needle_u8;
        const mbfl_string *haystack_u8, *needle_u8 = NULL;
-       const unsigned char *u8_tbl = mbfl_encoding_utf8.mblen_table;
+       const unsigned char *offset_pointer;
 
        if (haystack->encoding->no_encoding != mbfl_no_encoding_utf8) {
                mbfl_string_init(&_haystack_u8);
@@ -843,6 +874,12 @@ mbfl_strpos(
                needle_u8 = needle;
        }
 
+       offset_pointer = mbfl_find_offset_utf8(haystack_u8, offset);
+       if (!offset_pointer) {
+               result = MBFL_ERROR_OFFSET;
+               goto out;
+       }
+
        result = MBFL_ERROR_NOT_FOUND;
        if (haystack_u8->len < needle_u8->len) {
                goto out;
@@ -850,15 +887,6 @@ mbfl_strpos(
 
        if (needle_u8->len == 0) {
                size_t haystack_length = mbfl_strlen(haystack_u8);
-               /* Check if offset is out of bound */
-               if (
-                       (offset > 0 && offset > haystack_length)
-                       || (offset < 0 && -offset > haystack_length)
-               ) {
-                       result = -16;
-                       goto out;
-               }
-
                if (offset < 0) {
                        result = haystack_length + offset;
                } else if (reverse) {
@@ -883,15 +911,7 @@ mbfl_strpos(
                        jtbl[needle_u8_val[i]] = needle_u8_len - i;
                }
                e = haystack_u8_val + haystack_u8->len;
-               p = haystack_u8_val;
-               while (offset-- > 0) {
-                       if (p >= e) {
-                               result = MBFL_ERROR_OFFSET;
-                               goto out;
-                       }
-                       p += u8_tbl[*p];
-               }
-               p += needle_u8_len;
+               p = offset_pointer + needle_u8_len;
                if (p > e) {
                        goto out;
                }
@@ -968,14 +988,7 @@ mbfl_strpos(
                                }
                        }
                } else {
-                       const unsigned char *ee = haystack_u8_val + haystack_u8->len;
-                       while (offset-- > 0) {
-                               if (e >= ee) {
-                                       result = MBFL_ERROR_OFFSET;
-                                       goto out;
-                               }
-                               e += u8_tbl[*e];
-                       }
+                       e = offset_pointer;
                }
                if (p < e + needle_u8_len) {
                        goto out;
index 58b2f50049f63c64dbdba211db67de685ca400fa..3ee574db23793e039c43e684177cbc66ad1a1346 100644 (file)
@@ -2079,6 +2079,22 @@ PHP_FUNCTION(mb_strlen)
 }
 /* }}} */
 
+static void handle_strpos_error(size_t error) {
+       switch (error) {
+       case MBFL_ERROR_NOT_FOUND:
+               break;
+       case MBFL_ERROR_ENCODING:
+               php_error_docref(NULL, E_WARNING, "Unknown encoding or conversion error");
+               break;
+       case MBFL_ERROR_OFFSET:
+               php_error_docref(NULL, E_WARNING, "Offset not contained in string");
+               break;
+       default:
+               php_error_docref(NULL, E_WARNING, "Unknown error in mb_strpos");
+               break;
+       }
+}
+
 /* {{{ proto int mb_strpos(string haystack, string needle [, int offset [, string encoding]])
    Find position of first occurrence of a string within another */
 PHP_FUNCTION(mb_strpos)
@@ -2099,34 +2115,11 @@ PHP_FUNCTION(mb_strpos)
                RETURN_FALSE;
        }
 
-       if (offset != 0) {
-               size_t slen = mbfl_strlen(&haystack);
-               if (offset < 0) {
-                       offset += slen;
-               }
-               if (offset < 0 || offset > slen) {
-                       php_error_docref(NULL, E_WARNING, "Offset not contained in string");
-                       RETURN_FALSE;
-               }
-       }
-
        n = mbfl_strpos(&haystack, &needle, offset, reverse);
        if (!mbfl_is_error(n)) {
                RETVAL_LONG(n);
        } else {
-               switch (n) {
-               case MBFL_ERROR_NOT_FOUND:
-                       break;
-               case MBFL_ERROR_ENCODING:
-                       php_error_docref(NULL, E_WARNING, "Unknown encoding or conversion error");
-                       break;
-               case MBFL_ERROR_OFFSET:
-                       php_error_docref(NULL, E_WARNING, "Offset not contained in string");
-                       break;
-               default:
-                       php_error_docref(NULL, E_WARNING, "Unknown error in mb_strpos");
-                       break;
-               }
+               handle_strpos_error(n);
                RETVAL_FALSE;
        }
 }
@@ -2150,19 +2143,11 @@ PHP_FUNCTION(mb_strrpos)
                RETURN_FALSE;
        }
 
-       if (offset != 0) {
-               size_t haystack_char_len = mbfl_strlen(&haystack);
-               if ((offset > 0 && offset > haystack_char_len) ||
-                       (offset < 0 && -offset > haystack_char_len)) {
-                       php_error_docref(NULL, E_WARNING, "Offset is greater than the length of haystack string");
-                       RETURN_FALSE;
-               }
-       }
-
        n = mbfl_strpos(&haystack, &needle, offset, 1);
        if (!mbfl_is_error(n)) {
                RETVAL_LONG(n);
        } else {
+               handle_strpos_error(n);
                RETVAL_FALSE;
        }
 }
index 5585ba39630464e37c24413b266d47808db353f5..b353efaf77c954c6e71ed3dfc0965e928f23bf4e 100644 (file)
@@ -41,12 +41,12 @@ foreach ($offsets as $i) {
 -- Offset is -25 --
 Multibyte String:
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 ASCII String:
 mb_strrpos:
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 strrpos:
 Offset not contained in string
@@ -54,12 +54,12 @@ Offset not contained in string
 -- Offset is -24 --
 Multibyte String:
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 ASCII String:
 mb_strrpos:
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 strrpos:
 Offset not contained in string
index 268917bbd87d014dc01a1a90cba8365785e5d291..9f2f3c1b28029887e344e56a6ab5e02879d9a809 100644 (file)
@@ -168,7 +168,7 @@ bool(false)
 bool(false)
 > Offset: 12
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 > Offset: -1
 int(8)
@@ -178,7 +178,7 @@ int(8)
 int(4)
 > Offset: -20
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 
 ------- strripos -----------
diff --git a/ext/mbstring/tests/mb_strpos_offset_errors.phpt b/ext/mbstring/tests/mb_strpos_offset_errors.phpt
new file mode 100644 (file)
index 0000000..0a8fab3
--- /dev/null
@@ -0,0 +1,39 @@
+--TEST--
+Offset errors for various strpos functions
+--FILE--
+<?php
+
+var_dump(mb_strpos("f", "bar", 3));
+var_dump(mb_strpos("f", "bar", -3));
+var_dump(mb_strrpos("f", "bar", 3));
+var_dump(mb_strrpos("f", "bar", -3));
+var_dump(mb_stripos("f", "bar", 3));
+var_dump(mb_stripos("f", "bar", -3));
+var_dump(mb_strripos("f", "bar", 3));
+var_dump(mb_strripos("f", "bar", -3));
+
+?>
+--EXPECTF--
+Warning: mb_strpos(): Offset not contained in string in %s on line %d
+bool(false)
+
+Warning: mb_strpos(): Offset not contained in string in %s on line %d
+bool(false)
+
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
+bool(false)
+
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
+bool(false)
+
+Warning: mb_stripos(): Offset not contained in string in %s on line %d
+bool(false)
+
+Warning: mb_stripos(): Offset not contained in string in %s on line %d
+bool(false)
+
+Warning: mb_strripos(): Offset is greater than the length of haystack string in %s on line %d
+bool(false)
+
+Warning: mb_strripos(): Offset is greater than the length of haystack string in %s on line %d
+bool(false)
index a56c9c364b8f2843331c3e65f101f095a9763135..41e4bf5239e5baa07a5bffb413a7ef9474a3993c 100644 (file)
@@ -58,12 +58,12 @@ int(5)
 
 -- ASCII string with out of bound positive offset --
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 
 -- ASCII string with out of bound negative offset --
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 
 -- Multi-byte string without offset --
@@ -77,10 +77,10 @@ int(19)
 
 -- Multi-byte string with out of bound positive offset --
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)
 
 -- Multi-byte string with out of bound negative offset --
 
-Warning: mb_strrpos(): Offset is greater than the length of haystack string in %s on line %d
+Warning: mb_strrpos(): Offset not contained in string in %s on line %d
 bool(false)