Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Zend/zend_operators: fix casting underflowed unsigned to signed
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.
  • Loading branch information
MaxKellermann committed Mar 21, 2022
commit 3858649dd4cb2a50fd344040294259cc3d5a354a
2 changes: 1 addition & 1 deletion Zend/tests/006.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@ int(0)
int(-3)
int(0)
int(0)
int(2)
int(1)
int(0)
int(0)
12 changes: 6 additions & 6 deletions Zend/zend_operators.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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);
}
/* }}} */

Expand All @@ -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));
}
/* }}} */

Expand All @@ -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);
}
/* }}} */

Expand All @@ -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));
}
/* }}} */

Expand Down
6 changes: 6 additions & 0 deletions Zend/zend_portability.h
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,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 */
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/tests/strings/bug40754.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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) ""
2 changes: 1 addition & 1 deletion ext/standard/tests/strings/bug54454.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
2 changes: 1 addition & 1 deletion ext/standard/tests/strings/strncasecmp_variation7.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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 ***
4 changes: 2 additions & 2 deletions ext/standard/tests/strings/strncasecmp_variation9.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion ext/standard/tests/strings/strncmp_variation7.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ echo "*** Done ***\n";
?>
--EXPECT--
*** Test strncmp() function: Checking with the null terminated strings ***
int(5)
int(1)
*** Done ***