Don't throw for out of bounds offsets in strspn()

Make strspn($str1, $str2, $offset, $length) behaviorally
equivalent to strspn(substr($str1, $offset, $length), $str2)
by not throwing for out of bounds offset.

There have been two reports that this change cause issues,
including bug #80285.
This commit is contained in:
Nikita Popov 2020-10-27 11:23:49 +01:00
parent 76e4bf3068
commit d776d25a8e
8 changed files with 4791 additions and 4820 deletions

View file

@ -532,8 +532,6 @@ PHP 8.0 UPGRADE NOTES
. parse_str() can no longer be used without specifying a result array.
. fgetss() has been removed.
. The string.strip_tags filter has been removed.
. strspn() and strcspn() now throw a ValueError when the start or length
argument exceed the bounds of the string.
. The needle argument of strpos(), strrpos(), stripos(), strripos(), strstr(),
strchr(), strrchr(), and stristr() will now always be interpreted as a
string. Previously non-string needles were interpreted as an ASCII code

View file

@ -258,22 +258,25 @@ static void php_spn_common_handler(INTERNAL_FUNCTION_PARAMETERS, int behavior) /
Z_PARAM_LONG_OR_NULL(len, len_is_null)
ZEND_PARSE_PARAMETERS_END();
size_t remain_len = ZSTR_LEN(s11);
if (start < 0) {
start += (zend_long)ZSTR_LEN(s11);
start += remain_len;
if (start < 0) {
start = 0;
}
if (start < 0 || (size_t)start > ZSTR_LEN(s11)) {
zend_argument_value_error(3, "must be contained in argument #1 ($str)");
RETURN_THROWS();
} else if ((size_t) start > remain_len) {
start = remain_len;
}
size_t remain_len = ZSTR_LEN(s11) - start;
remain_len -= start;
if (!len_is_null) {
if (len < 0) {
len += remain_len;
if (len < 0) {
len = 0;
}
if (len < 0 || (size_t)len > remain_len) {
zend_argument_value_error(4, "must be contained in argument #1 ($str)");
RETURN_THROWS();
} else if ((size_t) len > remain_len) {
len = remain_len;
}
} else {
len = remain_len;

View file

@ -7,18 +7,8 @@ $v = 2147483647;
var_dump(substr("abcde", 1, $v));
var_dump(substr_replace("abcde", "x", $v, $v));
try {
var_dump(strspn("abcde", "abc", $v, $v));
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}
try {
var_dump(strcspn("abcde", "abc", $v, $v));
} catch (ValueError $exception) {
echo $exception->getMessage() . "\n";
}
try {
var_dump(substr_count("abcde", "abc", $v, $v));
@ -88,8 +78,8 @@ var_dump(substr("abcde", $v, $v));
--EXPECT--
string(4) "bcde"
string(6) "abcdex"
strspn(): Argument #3 ($offset) must be contained in argument #1 ($str)
strcspn(): Argument #3 ($offset) must be contained in argument #1 ($str)
int(0)
int(0)
substr_count(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
substr_compare(): Argument #3 ($offset) must be contained in argument #1 ($main_str)
stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)

View file

@ -9,11 +9,7 @@ var_dump($b);
var_dump(strcspn($a,$b));
var_dump(strcspn($a,$b,9));
var_dump(strcspn($a,$b,9,6));
try {
var_dump(strcspn('a', 'B', 1, 2147483647));
} catch (ValueError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECT--
string(25) "22222222aaaa bbb1111 cccc"
@ -21,4 +17,4 @@ string(4) "1234"
int(0)
int(7)
int(6)
strcspn(): Argument #4 ($length) must be contained in argument #1 ($str)
int(0)

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff