Skip to content

Commit dd36abe

Browse files
committed
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.
1 parent 733023b commit dd36abe

File tree

2 files changed

+12
-6
lines changed

2 files changed

+12
-6
lines changed

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
@@ -457,6 +457,12 @@ extern "C++" {
457457
#define ZEND_TRUTH(x) ((x) ? 1 : 0)
458458
#define ZEND_LOG_XOR(a, b) (ZEND_TRUTH(a) ^ ZEND_TRUTH(b))
459459

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

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

0 commit comments

Comments
 (0)