Skip to content

Commit fbb156d

Browse files
committed
Fixed int32 underflow on DateTime::createFromTimestamp
1 parent a906481 commit fbb156d

File tree

3 files changed

+132
-65
lines changed

3 files changed

+132
-65
lines changed

ext/date/php_date.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,12 +2522,13 @@ PHPAPI void php_date_initialize_from_ts_long(php_date_obj *dateobj, zend_long se
25222522
PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts) /* {{{ */
25232523
{
25242524
double sec_dval = trunc(ts);
2525-
zend_long sec;
2526-
int usec;
2525+
zend_long sec = (zend_long)sec_dval;
2526+
int usec = (int)(fmod(ts, 1) * 1000000);
25272527

25282528
if (UNEXPECTED(isnan(sec_dval)
2529-
|| sec_dval >= (double)TIMELIB_LONG_MAX
2529+
|| sec_dval > (double)TIMELIB_LONG_MAX
25302530
|| sec_dval < (double)TIMELIB_LONG_MIN
2531+
|| (sec == TIMELIB_LONG_MIN && usec < 0)
25312532
)) {
25322533
zend_throw_error(
25332534
date_ce_date_range_error,
@@ -2539,9 +2540,6 @@ PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts)
25392540
return false;
25402541
}
25412542

2542-
sec = (zend_long)sec_dval;
2543-
usec = (int)(fmod(ts, 1) * 1000000);
2544-
25452543
if (UNEXPECTED(usec < 0)) {
25462544
sec = sec - 1;
25472545
usec = 1000000 + usec;

ext/date/tests/createFromTimestamp.phpt

Lines changed: 1 addition & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
--TEST--
22
Tests for DateTime[Immutable]::createFromTimestamp
3-
--SKIPIF--
4-
<?php
5-
if (PHP_INT_SIZE === 4) die('xfail fails on 32-bit');
6-
?>
73
--INI--
84
date.timezone=Europe/London
95
--FILE--
@@ -12,10 +8,6 @@ date.timezone=Europe/London
128
class MyDateTime extends DateTime {};
139
class MyDateTimeImmutable extends DateTimeImmutable {};
1410

15-
define('MAX_32BIT', 2147483647);
16-
// -2147483648 may not be expressed in a literal due to parsing peculiarities.
17-
define('MIN_32BIT', -2147483647 - 1);
18-
1911
$timestamps = array(
2012
1696883232,
2113
-1696883232,
@@ -26,9 +18,6 @@ $timestamps = array(
2618
0,
2719
0.0,
2820
-0.0,
29-
MAX_32BIT,
30-
MIN_32BIT,
31-
MIN_32BIT - 0.5,
3221
PHP_INT_MAX + 1024.0,
3322
PHP_INT_MIN - 1025.0,
3423
NAN,
@@ -212,54 +201,6 @@ DateTimeImmutable::createFromTimestamp(-0.0): object(DateTimeImmutable)#%d (3) {
212201
["timezone"]=>
213202
string(6) "+00:00"
214203
}
215-
DateTime::createFromTimestamp(2147483647): object(DateTime)#%d (3) {
216-
["date"]=>
217-
string(26) "2038-01-19 03:14:07.000000"
218-
["timezone_type"]=>
219-
int(1)
220-
["timezone"]=>
221-
string(6) "+00:00"
222-
}
223-
DateTimeImmutable::createFromTimestamp(2147483647): object(DateTimeImmutable)#%d (3) {
224-
["date"]=>
225-
string(26) "2038-01-19 03:14:07.000000"
226-
["timezone_type"]=>
227-
int(1)
228-
["timezone"]=>
229-
string(6) "+00:00"
230-
}
231-
DateTime::createFromTimestamp(-2147483648): object(DateTime)#%d (3) {
232-
["date"]=>
233-
string(26) "1901-12-13 20:45:52.000000"
234-
["timezone_type"]=>
235-
int(1)
236-
["timezone"]=>
237-
string(6) "+00:00"
238-
}
239-
DateTimeImmutable::createFromTimestamp(-2147483648): object(DateTimeImmutable)#%d (3) {
240-
["date"]=>
241-
string(26) "1901-12-13 20:45:52.000000"
242-
["timezone_type"]=>
243-
int(1)
244-
["timezone"]=>
245-
string(6) "+00:00"
246-
}
247-
DateTime::createFromTimestamp(-2147483648.5): object(DateTime)#%d (3) {
248-
["date"]=>
249-
string(26) "1901-12-13 20:45:51.500000"
250-
["timezone_type"]=>
251-
int(1)
252-
["timezone"]=>
253-
string(6) "+00:00"
254-
}
255-
DateTimeImmutable::createFromTimestamp(-2147483648.5): object(DateTimeImmutable)#%d (3) {
256-
["date"]=>
257-
string(26) "1901-12-13 20:45:51.500000"
258-
["timezone_type"]=>
259-
int(1)
260-
["timezone"]=>
261-
string(6) "+00:00"
262-
}
263204
DateTime::createFromTimestamp(%f): DateRangeError: Seconds must be a finite number between %i and %i, %f given
264205
DateTimeImmutable::createFromTimestamp(%f): DateRangeError: Seconds must be a finite number between %i and %i, %f given
265206
DateTime::createFromTimestamp(%f): DateRangeError: Seconds must be a finite number between %i and %i, %f given
@@ -286,3 +227,4 @@ MyDateTimeImmutable::createFromTimestamp(0): object(MyDateTimeImmutable)#%d (3)
286227
["timezone"]=>
287228
string(6) "+00:00"
288229
}
230+
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
--TEST--
2+
Tests for DateTime[Immutable]::createFromTimestamp 32bit variant
3+
--SKIPIF--
4+
<?php
5+
if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
6+
?>
7+
--INI--
8+
date.timezone=Europe/London
9+
--FILE--
10+
<?php
11+
12+
$timestamps = array(
13+
PHP_INT_MAX,
14+
PHP_INT_MIN,
15+
PHP_INT_MAX + 0.5,
16+
PHP_INT_MIN + 0.5,
17+
PHP_INT_MAX - 0.5,
18+
PHP_INT_MIN - 0.5,
19+
PHP_INT_MAX + 1024.0,
20+
PHP_INT_MIN - 1025.0,
21+
);
22+
23+
foreach ($timestamps as $ts) {
24+
echo 'DateTime::createFromTimestamp(' . var_export($ts, true) . '): ';
25+
try {
26+
var_dump(DateTime::createFromTimestamp($ts));
27+
} catch (Throwable $e) {
28+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
29+
}
30+
31+
echo 'DateTimeImmutable::createFromTimestamp(' . var_export($ts, true) . '): ';
32+
try {
33+
var_dump(DateTimeImmutable::createFromTimestamp($ts));
34+
} catch (Throwable $e) {
35+
echo get_class($e) . ': ' . $e->getMessage() . "\n";
36+
}
37+
}
38+
39+
?>
40+
--EXPECTF--
41+
DateTime::createFromTimestamp(2147483647): object(DateTime)#%d (3) {
42+
["date"]=>
43+
string(26) "2038-01-19 03:14:07.000000"
44+
["timezone_type"]=>
45+
int(1)
46+
["timezone"]=>
47+
string(6) "+00:00"
48+
}
49+
DateTimeImmutable::createFromTimestamp(2147483647): object(DateTimeImmutable)#%d (3) {
50+
["date"]=>
51+
string(26) "2038-01-19 03:14:07.000000"
52+
["timezone_type"]=>
53+
int(1)
54+
["timezone"]=>
55+
string(6) "+00:00"
56+
}
57+
DateTime::createFromTimestamp(-2147483647-1): object(DateTime)#%d (3) {
58+
["date"]=>
59+
string(26) "1901-12-13 20:45:52.000000"
60+
["timezone_type"]=>
61+
int(1)
62+
["timezone"]=>
63+
string(6) "+00:00"
64+
}
65+
DateTimeImmutable::createFromTimestamp(-2147483647-1): object(DateTimeImmutable)#%d (3) {
66+
["date"]=>
67+
string(26) "1901-12-13 20:45:52.000000"
68+
["timezone_type"]=>
69+
int(1)
70+
["timezone"]=>
71+
string(6) "+00:00"
72+
}
73+
DateTime::createFromTimestamp(2147483647.5): object(DateTime)#%d (3) {
74+
["date"]=>
75+
string(26) "2038-01-19 03:14:07.500000"
76+
["timezone_type"]=>
77+
int(1)
78+
["timezone"]=>
79+
string(6) "+00:00"
80+
}
81+
DateTimeImmutable::createFromTimestamp(2147483647.5): object(DateTimeImmutable)#%d (3) {
82+
["date"]=>
83+
string(26) "2038-01-19 03:14:07.500000"
84+
["timezone_type"]=>
85+
int(1)
86+
["timezone"]=>
87+
string(6) "+00:00"
88+
}
89+
DateTime::createFromTimestamp(-2147483647.5): object(DateTime)#%d (3) {
90+
["date"]=>
91+
string(26) "1901-12-13 20:45:52.500000"
92+
["timezone_type"]=>
93+
int(1)
94+
["timezone"]=>
95+
string(6) "+00:00"
96+
}
97+
DateTimeImmutable::createFromTimestamp(-2147483647.5): object(DateTimeImmutable)#%d (3) {
98+
["date"]=>
99+
string(26) "1901-12-13 20:45:52.500000"
100+
["timezone_type"]=>
101+
int(1)
102+
["timezone"]=>
103+
string(6) "+00:00"
104+
}
105+
DateTime::createFromTimestamp(2147483646.5): object(DateTime)#%d (3) {
106+
["date"]=>
107+
string(26) "2038-01-19 03:14:06.500000"
108+
["timezone_type"]=>
109+
int(1)
110+
["timezone"]=>
111+
string(6) "+00:00"
112+
}
113+
DateTimeImmutable::createFromTimestamp(2147483646.5): object(DateTimeImmutable)#%d (3) {
114+
["date"]=>
115+
string(26) "2038-01-19 03:14:06.500000"
116+
["timezone_type"]=>
117+
int(1)
118+
["timezone"]=>
119+
string(6) "+00:00"
120+
}
121+
DateTime::createFromTimestamp(-2147483648.5): DateRangeError: Seconds must be a finite number between -2147483648 and 2147483647, -2.14748e+9 given
122+
DateTimeImmutable::createFromTimestamp(-2147483648.5): DateRangeError: Seconds must be a finite number between -2147483648 and 2147483647, -2.14748e+9 given
123+
DateTime::createFromTimestamp(2147484671.0): DateRangeError: Seconds must be a finite number between -2147483648 and 2147483647, 2.14748e+9 given
124+
DateTimeImmutable::createFromTimestamp(2147484671.0): DateRangeError: Seconds must be a finite number between -2147483648 and 2147483647, 2.14748e+9 given
125+
DateTime::createFromTimestamp(-2147484673.0): DateRangeError: Seconds must be a finite number between -2147483648 and 2147483647, -2.14748e+9 given
126+
DateTimeImmutable::createFromTimestamp(-2147484673.0): DateRangeError: Seconds must be a finite number between -2147483648 and 2147483647, -2.14748e+9 given
127+

0 commit comments

Comments
 (0)