Add ZEND_THREEWAY_COMPARE() macro to fix casting underflowed unsigned to signed (#8220)

Casting a huge unsigned value to signed is implementation-defined
behavior in C.  By introducing the ZEND_THREEWAY_COMPARE() macro, we
can sidestep this integer overflow/underflow/casting problem.
This commit is contained in:
Max Kellermann 2022-06-08 14:24:18 +02:00 committed by GitHub
parent 89688b115d
commit c1a06704da
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 19 additions and 13 deletions

View File

@ -24,6 +24,6 @@ int(0)
int(-3)
int(0)
int(0)
int(2)
int(1)
int(0)
int(0)

View File

@ -2956,7 +2956,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const
}
retval = memcmp(s1, s2, MIN(len1, len2));
if (!retval) {
return (int)(len1 - len2);
return ZEND_THREEWAY_COMPARE(len1, len2);
} else {
return retval;
}
@ -2972,7 +2972,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, cons
}
retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
if (!retval) {
return (int)(MIN(length, len1) - MIN(length, len2));
return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
} else {
return retval;
}
@ -2997,7 +2997,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, c
}
}
return (int)(len1 - len2);
return ZEND_THREEWAY_COMPARE(len1, len2);
}
/* }}} */
@ -3018,7 +3018,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1,
}
}
return (int)(MIN(length, len1) - MIN(length, len2));
return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
}
/* }}} */
@ -3040,7 +3040,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1,
}
}
return (int)(len1 - len2);
return ZEND_THREEWAY_COMPARE(len1, len2);
}
/* }}} */
@ -3061,7 +3061,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1
}
}
return (int)(MIN(length, len1) - MIN(length, len2));
return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
}
/* }}} */

View File

@ -456,6 +456,12 @@ extern "C++" {
#define ZEND_TRUTH(x) ((x) ? 1 : 0)
#define ZEND_LOG_XOR(a, b) (ZEND_TRUTH(a) ^ ZEND_TRUTH(b))
/**
* Do a three-way comparison of two integers and returns -1, 0 or 1
* depending on whether #a is smaller, equal or larger than #b.
*/
#define ZEND_THREEWAY_COMPARE(a, b) ((a) == (b) ? 0 : ((a) < (b) ? -1 : 1))
#define ZEND_MAX_RESERVED_RESOURCES 6
/* excpt.h on Digital Unix 4.0 defines function_table */

View File

@ -90,6 +90,6 @@ stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
strrpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
int(2)
int(1)
string(8) "abcdeabc"
string(0) ""

View File

@ -5,4 +5,4 @@ Bug #54454 (substr_compare incorrectly reports equality in some cases)
var_dump(substr_compare('/', '/asd', 0, 4));
?>
--EXPECT--
int(-3)
int(-1)

View File

@ -17,6 +17,6 @@ echo "*** Done ***\n";
?>
--EXPECT--
*** Test strncasecmp() function: with null terminated strings and binary inputs ***
int(5)
int(1)
int(-119)
*** Done ***

View File

@ -71,9 +71,9 @@ echo "*** Done ***\n";
--EXPECT--
*** Test strncasecmp() function: with here-doc strings ***
int(0)
int(63)
int(1)
int(0)
int(83)
int(1)
int(0)
int(-1)
int(0)

View File

@ -15,5 +15,5 @@ echo "*** Done ***\n";
?>
--EXPECT--
*** Test strncmp() function: Checking with the null terminated strings ***
int(5)
int(1)
*** Done ***