Commit b8dad9314c1 for php.net
commit b8dad9314c1e225a1a2d50608e4e7d478c34365c
Merge: 3f6f38bc12b dc9e21b81c1
Author: Ilija Tovilo <ilija.tovilo@me.com>
Date: Wed May 6 13:10:12 2026 +0200
GHSA-m8rr-4c36-8gq4: Consistently pass unsigned char to ctype.h functions
Fixes GHSA-m8rr-4c36-8gq4
Fixes CVE-2026-7258
diff --cc ext/filter/logical_filters.c
index 2dec2361141,634496027c8..017ac41a65a
--- a/ext/filter/logical_filters.c
+++ b/ext/filter/logical_filters.c
@@@ -535,22 -528,22 +535,22 @@@ static bool php_filter_validate_domain_
}
/* First char must be alphanumeric */
- if(*s == '.' || (hostname && !isalnum((int)*(unsigned char *)s))) {
+ if(*s == '.' || (hostname && !isalnum((unsigned char)*s))) {
- return 0;
+ return false;
}
while (s < e) {
if (*s == '.') {
/* The first and the last character of a label must be alphanumeric */
- if (*(s + 1) == '.' || (hostname && (!isalnum((int)*(unsigned char *)(s - 1)) || !isalnum((int)*(unsigned char *)(s + 1))))) {
+ if (*(s + 1) == '.' || (hostname && (!isalnum((unsigned char)s[-1]) || !isalnum((unsigned char)s[1])))) {
- return 0;
+ return false;
}
/* Reset label length counter */
i = 1;
} else {
- if (i > 63 || (hostname && (*s != '-' || *(s + 1) == '\0') && !isalnum((int)*(unsigned char *)s))) {
+ if (i > 63 || (hostname && (*s != '-' || *(s + 1) == '\0') && !isalnum((unsigned char)*s))) {
- return 0;
+ return false;
}
i++;
@@@ -572,32 -564,33 +572,32 @@@ zend_result php_filter_validate_domain(
}
/* }}} */
-static int is_userinfo_valid(zend_string *str)
+static bool is_userinfo_valid(const zend_string *str)
{
- const char *valid = "-._~!$&'()*+,;=:";
const char *p = ZSTR_VAL(str);
while (p - ZSTR_VAL(str) < ZSTR_LEN(str)) {
+ static const char *valid = "-._~!$&'()*+,;=:";
- if (isalpha(*p) || isdigit(*p) || strchr(valid, *p)) {
+ if (isalpha((unsigned char)*p) || isdigit((unsigned char)*p) || strchr(valid, *p)) {
p++;
- } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit(*(p+1)) && isxdigit(*(p+2))) {
+ } else if (*p == '%' && p - ZSTR_VAL(str) <= ZSTR_LEN(str) - 3 && isdigit((unsigned char)p[1]) && isxdigit((unsigned char)p[2])) {
p += 3;
} else {
- return 0;
+ return false;
}
}
- return 1;
+ return true;
}
-static bool php_filter_is_valid_ipv6_hostname(const char *s, size_t l)
+static bool php_filter_is_valid_ipv6_hostname(const zend_string *s)
{
- const char *e = s + l;
+ const char *e = ZSTR_VAL(s) + ZSTR_LEN(s);
const char *t = e - 1;
- return *s == '[' && *t == ']' && _php_filter_validate_ipv6(s + 1, l - 2, NULL);
+ return *ZSTR_VAL(s) == '[' && *t == ']' && _php_filter_validate_ipv6(ZSTR_VAL(s) + 1, ZSTR_LEN(s) - 2, NULL);
}
-void php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
+zend_result php_filter_validate_url(PHP_INPUT_FILTER_PARAM_DECL) /* {{{ */
{
- php_url *url;
size_t old_len = Z_STRLEN_P(value);
php_filter_url(value, flags, option_array, charset);
diff --cc ext/ftp/ftp.c
index 5291a1f172d,36a0d1697ec..a6afed74859
--- a/ext/ftp/ftp.c
+++ b/ext/ftp/ftp.c
@@@ -785,16 -855,16 +785,16 @@@ bool ftp_pasv(ftpbuf_t *ftp, int pasv
#endif
if (!ftp_putcmd(ftp, "PASV", sizeof("PASV")-1, NULL, (size_t) 0)) {
- return 0;
+ return false;
}
if (!ftp_getresp(ftp) || ftp->resp != 227) {
- return 0;
+ return false;
}
/* parse out the IP and port */
- for (ptr = ftp->inbuf; *ptr && !isdigit(*ptr); ptr++);
+ for (ptr = ftp->inbuf; *ptr && !isdigit((unsigned char)*ptr); ptr++);
n = sscanf(ptr, "%lu,%lu,%lu,%lu,%lu,%lu", &b[0], &b[1], &b[2], &b[3], &b[4], &b[5]);
if (n != 6) {
- return 0;
+ return false;
}
for (n = 0; n < 6; n++) {
ipbox.c[n] = (unsigned char) b[n];
@@@ -1284,8 -1392,8 +1284,8 @@@ static bool ftp_getresp(ftpbuf_t *ftp
}
/* translate the tag */
- if (!isdigit(ftp->inbuf[0]) || !isdigit(ftp->inbuf[1]) || !isdigit(ftp->inbuf[2])) {
+ if (!isdigit((unsigned char)ftp->inbuf[0]) || !isdigit((unsigned char)ftp->inbuf[1]) || !isdigit((unsigned char)ftp->inbuf[2])) {
- return 0;
+ return false;
}
ftp->resp = 100 * (ftp->inbuf[0] - '0') + 10 * (ftp->inbuf[1] - '0') + (ftp->inbuf[2] - '0');
diff --cc ext/standard/url.c
index 504805484ef,c47e21af71b..7bfaa719a84
--- a/ext/standard/url.c
+++ b/ext/standard/url.c
@@@ -591,11 -588,11 +591,11 @@@ PHPAPI size_t php_url_decode_ex(char *d
if (*data == '+') {
*dest = ' ';
}
- else if (*data == '%' && src_len >= 2 && isxdigit((int) *(data + 1))
- && isxdigit((int) *(data + 2))) {
- else if (*data == '%' && len >= 2 && isxdigit((unsigned char)data[1])
++ else if (*data == '%' && src_len >= 2 && isxdigit((unsigned char)data[1])
+ && isxdigit((unsigned char)data[2])) {
*dest = (char) php_htoi(data + 1);
data += 2;
- len -= 2;
+ src_len -= 2;
} else {
*dest = *data;
}
@@@ -658,17 -640,18 +658,17 @@@ PHP_FUNCTION(rawurldecode
}
/* }}} */
-/* {{{ php_raw_url_decode */
-PHPAPI size_t php_raw_url_decode(char *str, size_t len)
+PHPAPI size_t php_raw_url_decode_ex(char *dest, const char *src, size_t src_len)
{
- char *dest = str;
- char *data = str;
+ char *dest_start = dest;
+ const char *data = src;
- while (len--) {
- if (*data == '%' && len >= 2 && isxdigit((unsigned char)data[1])
+ while (src_len--) {
- if (*data == '%' && src_len >= 2 && isxdigit((int) *(data + 1))
- && isxdigit((int) *(data + 2))) {
++ if (*data == '%' && src_len >= 2 && isxdigit((unsigned char)data[1])
+ && isxdigit((unsigned char)data[2])) {
*dest = (char) php_htoi(data + 1);
data += 2;
- len -= 2;
+ src_len -= 2;
} else {
*dest = *data;
}
diff --cc main/streams/streams.c
index 85d2947c28a,6feb8b7c01b..73fdc785721
--- a/main/streams/streams.c
+++ b/main/streams/streams.c
@@@ -1918,10 -1918,12 +1918,10 @@@ void php_shutdown_stream_wrappers(int m
/* Validate protocol scheme names during registration
* Must conform to /^[a-zA-Z0-9+.-]+$/
*/
-static inline zend_result php_stream_wrapper_scheme_validate(const char *protocol, unsigned int protocol_len)
+static inline zend_result php_stream_wrapper_scheme_validate(const char *protocol, size_t protocol_len)
{
- unsigned int i;
-
- for(i = 0; i < protocol_len; i++) {
+ for (size_t i = 0; i < protocol_len; i++) {
- if (!isalnum((int)protocol[i]) &&
+ if (!isalnum((unsigned char)protocol[i]) &&
protocol[i] != '+' &&
protocol[i] != '-' &&
protocol[i] != '.') {