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
--- php.orig/Zend/zend_hash.h
+++ php/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; \
} \
} \
--- php.orig/Zend/tests/bug45877.phpt
+++ php/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
|