[php-src] Issue #12592: strcspn() odd behaviour with NUL bytes and empty mask
| From: | nielsdos | Date: | Wed, 01 Nov 2023 20:48:29 +0000 |
| Subject: | [php-src] Issue #12592: strcspn() odd behaviour with NUL bytes and empty mask | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-245716@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/12592
Author: nielsdos
### Description
The following code:
```php
<?php
var_dump(strcspn("abc\0def", " "));
var_dump(strcspn("abc\0def", ""));
```
Resulted in this output:
```
int(7)
int(3)
```
But I expected this output instead:
```
int(7)
int(7)
```
Looking at the description of strcspn:
> Returns the length of the initial segment of string which does not contain any of the
> characters in characters.
IOW, if the mask is empty, the stop condition is never met so the total length of the string must be
returned, no?
I discovered this while I was working on an optimization for this function similar to what I did for
strspn.
This has been wrong since 1999: a15916a47aba3e89d2b6cad8533868c7ee958c25
There are actually tests that check this behaviour, but I think that's just incidental as the
test date from way later than 1999.
The reason this happens is because
php_strcspn accesses *s2 even if it is
empty, thus reading a NUL byte out of bounds and thinking that the NUL is part of the mask.
Fixing this is trivial however, although I wouldn't recommend doing this in stable branches as
it is a behaviour change, although a weird one:
```diff
diff --git a/ext/standard/string.c b/ext/standard/string.c
index 8beedfe818..b5deb20403 100644
--- a/ext/standard/string.c
+++ b/ext/standard/string.c
@@ -1640,16 +1640,16 @@ PHPAPI size_t php_strcspn(const char *s1, const char *s2, const char
*s1_end, co
const char *p, *spanp;
char c = *s1;
- for (p = s1;;) {
- spanp = s2;
- do {
- if (*spanp == c || p == s1_end) {
+ for (p = s1; p < s1_end;) {
+ for (spanp = s2; spanp < s2_end; spanp++) {
+ if (*spanp == c) {
return p - s1;
}
- } while (spanp++ < (s2_end - 1));
+ }
c = *++p;
}
- /* NOTREACHED */
+
+ return p - s1;
}
/* }}} */
```
I'd say: let's fix it only in master?
### PHP Version
Every version since 1999
### Operating System
_No response_