Skip to content

Commit c1a0670

Browse files
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.
1 parent 89688b1 commit c1a0670

File tree

8 files changed

+19
-13
lines changed

8 files changed

+19
-13
lines changed

Zend/tests/006.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ int(0)
2424
int(-3)
2525
int(0)
2626
int(0)
27-
int(2)
27+
int(1)
2828
int(0)
2929
int(0)

Zend/zend_operators.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2956,7 +2956,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const
29562956
}
29572957
retval = memcmp(s1, s2, MIN(len1, len2));
29582958
if (!retval) {
2959-
return (int)(len1 - len2);
2959+
return ZEND_THREEWAY_COMPARE(len1, len2);
29602960
} else {
29612961
return retval;
29622962
}
@@ -2972,7 +2972,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, cons
29722972
}
29732973
retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
29742974
if (!retval) {
2975-
return (int)(MIN(length, len1) - MIN(length, len2));
2975+
return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
29762976
} else {
29772977
return retval;
29782978
}
@@ -2997,7 +2997,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, c
29972997
}
29982998
}
29992999

3000-
return (int)(len1 - len2);
3000+
return ZEND_THREEWAY_COMPARE(len1, len2);
30013001
}
30023002
/* }}} */
30033003

@@ -3018,7 +3018,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1,
30183018
}
30193019
}
30203020

3021-
return (int)(MIN(length, len1) - MIN(length, len2));
3021+
return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
30223022
}
30233023
/* }}} */
30243024

@@ -3040,7 +3040,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1,
30403040
}
30413041
}
30423042

3043-
return (int)(len1 - len2);
3043+
return ZEND_THREEWAY_COMPARE(len1, len2);
30443044
}
30453045
/* }}} */
30463046

@@ -3061,7 +3061,7 @@ ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1
30613061
}
30623062
}
30633063

3064-
return (int)(MIN(length, len1) - MIN(length, len2));
3064+
return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
30653065
}
30663066
/* }}} */
30673067

Zend/zend_portability.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,12 @@ extern "C++" {
456456
#define ZEND_TRUTH(x) ((x) ? 1 : 0)
457457
#define ZEND_LOG_XOR(a, b) (ZEND_TRUTH(a) ^ ZEND_TRUTH(b))
458458

459+
/**
460+
* Do a three-way comparison of two integers and returns -1, 0 or 1
461+
* depending on whether #a is smaller, equal or larger than #b.
462+
*/
463+
#define ZEND_THREEWAY_COMPARE(a, b) ((a) == (b) ? 0 : ((a) < (b) ? -1 : 1))
464+
459465
#define ZEND_MAX_RESERVED_RESOURCES 6
460466

461467
/* excpt.h on Digital Unix 4.0 defines function_table */

ext/standard/tests/strings/bug40754.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,6 @@ stripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
9090
strrpos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
9191
strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
9292
strripos(): Argument #3 ($offset) must be contained in argument #1 ($haystack)
93-
int(2)
93+
int(1)
9494
string(8) "abcdeabc"
9595
string(0) ""

ext/standard/tests/strings/bug54454.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ Bug #54454 (substr_compare incorrectly reports equality in some cases)
55
var_dump(substr_compare('/', '/asd', 0, 4));
66
?>
77
--EXPECT--
8-
int(-3)
8+
int(-1)

ext/standard/tests/strings/strncasecmp_variation7.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,6 @@ echo "*** Done ***\n";
1717
?>
1818
--EXPECT--
1919
*** Test strncasecmp() function: with null terminated strings and binary inputs ***
20-
int(5)
20+
int(1)
2121
int(-119)
2222
*** Done ***

ext/standard/tests/strings/strncasecmp_variation9.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ echo "*** Done ***\n";
7171
--EXPECT--
7272
*** Test strncasecmp() function: with here-doc strings ***
7373
int(0)
74-
int(63)
74+
int(1)
7575
int(0)
76-
int(83)
76+
int(1)
7777
int(0)
7878
int(-1)
7979
int(0)

ext/standard/tests/strings/strncmp_variation7.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,5 +15,5 @@ echo "*** Done ***\n";
1515
?>
1616
--EXPECT--
1717
*** Test strncmp() function: Checking with the null terminated strings ***
18-
int(5)
18+
int(1)
1919
*** Done ***

0 commit comments

Comments
 (0)