1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
Author: Sean Finney <seanius@debian.org>
Description: Another integer overflow/underflow logic fix.
Once again, don't rely on undefined behavior and instead detect
the overflow/underflow conditions intelligently.
Bug: http://bugs.php.net/bug.php?id=51008
Bug-Debian: http://bugs.debian.org/570144
--- a/Zend/zend_hash.h
+++ b/Zend/zend_hash.h
@@ -306,9 +306,11 @@ END_EXTERN_C()
#define ZEND_HANDLE_NUMERIC(key, length, func) do { \
register const char *tmp = key; \
+ int negative = 0; \
\
if (*tmp == '-') { \
tmp++; \
+ negative = 1; \
} \
if (*tmp >= '0' && *tmp <= '9') { /* possibly a numeric index */ \
const char *end = key + length - 1; \
@@ -322,19 +324,19 @@ END_EXTERN_C()
*tmp > '2')) { /* overflow */ \
break; \
} \
- idx = (*tmp - '0'); \
+ idx = ((negative)?-1:1) * (*tmp - '0'); \
while (++tmp != end && *tmp >= '0' && *tmp <= '9') { \
- idx = (idx * 10) + (*tmp - '0'); \
+ int digit = (*tmp - '0'); \
+ if ( (!negative) && idx <= (LONG_MAX-digit)/10 ) { \
+ idx = (idx * 10) + digit; \
+ } else if ( (negative) && idx >= (LONG_MIN+digit)/10 ) { \
+ idx = (idx * 10) - digit; \
+ } else { \
+ --tmp; /* overflow or underflow, make sure tmp != end */ \
+ break; \
+ } \
} \
if (tmp == end) { \
- if (*key == '-') { \
- idx = -idx; \
- if (idx > 0) { /* overflow */ \
- break; \
- } \
- } else if (idx < 0) { /* overflow */ \
- break; \
- } \
return func; \
} \
} \
--- a/Zend/tests/bug45877.phpt
+++ b/Zend/tests/bug45877.phpt
@@ -1,23 +1,40 @@
--TEST--
Bug #45877 (Array key '2147483647' left as string)
---INI--
-precision=16
--FILE--
<?php
-$keys = array(PHP_INT_MAX,
- (string) PHP_INT_MAX,
- (string) (-PHP_INT_MAX - 1),
- -PHP_INT_MAX - 1,
- (string) (PHP_INT_MAX + 1));
+$max = sprintf("%d", PHP_INT_MAX);
+switch($max) {
+case "2147483647": /* 32-bit systems */
+ $min = "-2147483648";
+ $overflow = "2147483648";
+ $underflow = "-2147483649";
+ break;
+case "9223372036854775807": /* 64-bit systems */
+ $min = "-9223372036854775808";
+ $overflow = "9223372036854775808";
+ $underflow = "-9223372036854775809";
+ break;
+default:
+ die("failed: unknown value for PHP_MAX_INT");
+ break;
+}
-var_dump(array_fill_keys($keys, 1));
-?>
---EXPECTF--
-array(3) {
- [%d7]=>
- int(1)
- [-%d8]=>
- int(1)
- ["%s"]=>
- int(1)
+function test_value($val, $msg) {
+ $a = array($val => 1);
+ $keys = array_keys($a);
+ if ($val == $keys[0]) $result = "ok";
+ else $result = "failed ($val != $keys[0])";
+ echo "$msg: $result\n";
}
+
+test_value($max, "max");
+test_value($overflow, "overflow");
+test_value($min, "min");
+test_value($underflow, "underflow");
+
+?>
+--EXPECT--
+max: ok
+overflow: ok
+min: ok
+underflow: ok
|