Skip to content

Commit 839bbf1

Browse files
committed
Extend isxdigit() UB fix to quoted_printable_decode and stripcslashes
Same signed-char UB as in url_decode: isxdigit() is called on byte values from char-pointers (str_in in quoted_printable_decode, source in php_stripcslashes), which sign-extend to negative int on signed-char platforms when the byte has its high bit set.
1 parent 68be6fe commit 839bbf1

3 files changed

Lines changed: 7 additions & 6 deletions

File tree

NEWS

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,9 @@ PHP NEWS
162162
. Fix NUL byte truncation in sqlite3 TEXT column handling. (ndossche)
163163

164164
- Standard:
165-
. Fixed bug GH-21738 (undefined behavior in url_decode functions when
166-
passing non-ASCII bytes to isxdigit()). (lacatoire)
165+
. Fixed bug GH-21738 (undefined behavior when passing non-ASCII bytes to
166+
isxdigit() in url_decode, quoted_printable_decode and stripcslashes).
167+
(lacatoire)
167168
. Fixed bug GH-19926 (reset internal pointer earlier while splicing array
168169
while COW violation flag is still set). (alexandre-daubois)
169170
. Added form feed (\f) in the default trimmed characters of trim(), rtrim()

ext/standard/quot_print.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,8 @@ PHP_FUNCTION(quoted_printable_decode)
210210
switch (str_in[i]) {
211211
case '=':
212212
if (str_in[i + 1] && str_in[i + 2] &&
213-
isxdigit((int) str_in[i + 1]) &&
214-
isxdigit((int) str_in[i + 2]))
213+
isxdigit((unsigned char) str_in[i + 1]) &&
214+
isxdigit((unsigned char) str_in[i + 2]))
215215
{
216216
ZSTR_VAL(str_out)[j++] = (php_hex2int((int) str_in[i + 1]) << 4)
217217
+ php_hex2int((int) str_in[i + 2]);

ext/standard/string.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3760,9 +3760,9 @@ PHPAPI void php_stripcslashes(zend_string *str)
37603760
case 'f': *target++='\f'; nlen--; break;
37613761
case '\\': *target++='\\'; nlen--; break;
37623762
case 'x':
3763-
if (source+1 < end && isxdigit((int)(*(source+1)))) {
3763+
if (source+1 < end && isxdigit((unsigned char)(*(source+1)))) {
37643764
numtmp[0] = *++source;
3765-
if (source+1 < end && isxdigit((int)(*(source+1)))) {
3765+
if (source+1 < end && isxdigit((unsigned char)(*(source+1)))) {
37663766
numtmp[1] = *++source;
37673767
numtmp[2] = '\0';
37683768
nlen-=3;

0 commit comments

Comments
 (0)