Skip to content

Commit 1781833

Browse files
committed
Fixed int32 underflow on DateTime::createFromTimestamp
1 parent f6efd12 commit 1781833

File tree

3 files changed

+132
-61
lines changed

3 files changed

+132
-61
lines changed

ext/date/php_date.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2513,12 +2513,13 @@ PHPAPI void php_date_initialize_from_ts_long(php_date_obj *dateobj, zend_long se
25132513
PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts) /* {{{ */
25142514
{
25152515
double sec_dval = trunc(ts);
2516-
zend_long sec;
2517-
int usec;
2516+
zend_long sec = (zend_long)sec_dval;
2517+
int usec = (int)(fmod(ts, 1) * 1000000);
25182518

25192519
if (UNEXPECTED(isnan(sec_dval)
2520-
|| sec_dval >= (double)TIMELIB_LONG_MAX
2520+
|| sec_dval > (double)TIMELIB_LONG_MAX
25212521
|| sec_dval < (double)TIMELIB_LONG_MIN
2522+
|| (sec == TIMELIB_LONG_MIN && usec < 0)
25222523
)) {
25232524
zend_throw_error(
25242525
date_ce_date_range_error,
@@ -2530,9 +2531,6 @@ PHPAPI bool php_date_initialize_from_ts_double(php_date_obj *dateobj, double ts)
25302531
return false;
25312532
}
25322533

2533-
sec = (zend_long)sec_dval;
2534-
usec = (int)(fmod(ts, 1) * 1000000);
2535-
25362534
if (UNEXPECTED(usec < 0)) {
25372535
sec = sec - 1;
25382536
usec = 1000000 + usec;

ext/date/tests/createFromTimestamp.phpt

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,6 @@ date.timezone=Europe/London
88
class MyDateTime extends DateTime {};
99
class MyDateTimeImmutable extends DateTimeImmutable {};
1010

11-
define('MAX_32BIT', 2147483647);
12-
// -2147483648 may not be expressed in a literal due to parsing peculiarities.
13-
define('MIN_32BIT', -2147483647 - 1);
14-
1511
$timestamps = array(
1612
1696883232,
1713
-1696883232,
@@ -22,9 +18,6 @@ $timestamps = array(
2218
0,
2319
0.0,
2420
-0.0,
25-
MAX_32BIT,
26-
MIN_32BIT,
27-
MIN_32BIT - 0.5,
2821
PHP_INT_MAX + 1024.0,
2922
PHP_INT_MIN - 1025.0,
3023
NAN,
@@ -208,54 +201,6 @@ DateTimeImmutable::createFromTimestamp(-0.0): object(DateTimeImmutable)#%d (3) {
208201
["timezone"]=>
209202
string(6) "+00:00"
210203
}
211-
DateTime::createFromTimestamp(2147483647): object(DateTime)#%d (3) {
212-
["date"]=>
213-
string(26) "2038-01-19 03:14:07.000000"
214-
["timezone_type"]=>
215-
int(1)
216-
["timezone"]=>
217-
string(6) "+00:00"
218-
}
219-
DateTimeImmutable::createFromTimestamp(2147483647): object(DateTimeImmutable)#%d (3) {
220-
["date"]=>
221-
string(26) "2038-01-19 03:14:07.000000"
222-
["timezone_type"]=>
223-
int(1)
224-
["timezone"]=>
225-
string(6) "+00:00"
226-
}
227-
DateTime::createFromTimestamp(-2147483648): object(DateTime)#%d (3) {
228-
["date"]=>
229-
string(26) "1901-12-13 20:45:52.000000"
230-
["timezone_type"]=>
231-
int(1)
232-
["timezone"]=>
233-
string(6) "+00:00"
234-
}
235-
DateTimeImmutable::createFromTimestamp(-2147483648): object(DateTimeImmutable)#%d (3) {
236-
["date"]=>
237-
string(26) "1901-12-13 20:45:52.000000"
238-
["timezone_type"]=>
239-
int(1)
240-
["timezone"]=>
241-
string(6) "+00:00"
242-
}
243-
DateTime::createFromTimestamp(-2147483648.5): object(DateTime)#%d (3) {
244-
["date"]=>
245-
string(26) "1901-12-13 20:45:51.500000"
246-
["timezone_type"]=>
247-
int(1)
248-
["timezone"]=>
249-
string(6) "+00:00"
250-
}
251-
DateTimeImmutable::createFromTimestamp(-2147483648.5): object(DateTimeImmutable)#%d (3) {
252-
["date"]=>
253-
string(26) "1901-12-13 20:45:51.500000"
254-
["timezone_type"]=>
255-
int(1)
256-
["timezone"]=>
257-
string(6) "+00:00"
258-
}
259204
DateTime::createFromTimestamp(%f): DateRangeError: Seconds must be a finite number between %i and %i, %f given
260205
DateTimeImmutable::createFromTimestamp(%f): DateRangeError: Seconds must be a finite number between %i and %i, %f given
261206
DateTime::createFromTimestamp(%f): DateRangeError: Seconds must be a finite number between %i and %i, %f given
@@ -282,3 +227,4 @@ MyDateTimeImmutable::createFromTimestamp(0): object(MyDateTimeImmutable)#%d (3)
282227
["timezone"]=>
283228
string(6) "+00:00"
284229
}
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)