Skip to content

Commit 16c0e57

Browse files
committed
Fix GH-14709 overflow on recurrences for DatePeriod::__construct
close GH-14710
1 parent a23ecc0 commit 16c0e57

File tree

5 files changed

+47
-10
lines changed

5 files changed

+47
-10
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ PHP NEWS
99
. Fixed bug GH-17101 (AST->string does not reproduce constructor property
1010
promotion correctly). (nielsdos)
1111

12+
- Date:
13+
. Fixed bug GH-14709 DatePeriod::__construct() overflow on recurrences.
14+
(David Carlier)
15+
1216
- DBA:
1317
. Skip test if inifile is disabled. (orlitzky)
1418

ext/date/php_date.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4903,9 +4903,11 @@ static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_en
49034903

49044904
static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, zend_long recurrences)
49054905
{
4906-
if (dpobj->end == NULL && recurrences < 1) {
4906+
const zend_long max_recurrences = (INT_MAX - 8);
4907+
4908+
if (dpobj->end == NULL && (recurrences < 1 || recurrences > max_recurrences)) {
49074909
zend_string *func = get_active_function_or_method_name();
4908-
zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func));
4910+
zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater or equal to 1 and lower than " ZEND_LONG_FMT, ZSTR_VAL(func), max_recurrences + 1);
49094911
zend_string_release(func);
49104912
return false;
49114913
}
@@ -4914,8 +4916,17 @@ static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, ze
49144916
dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
49154917
dpobj->include_end_date = options & PHP_DATE_PERIOD_INCLUDE_END_DATE;
49164918

4917-
/* recurrrences */
4918-
dpobj->recurrences = recurrences + dpobj->include_start_date + dpobj->include_end_date;
4919+
/* recurrences */
4920+
recurrences += dpobj->include_start_date + dpobj->include_end_date;
4921+
4922+
if (UNEXPECTED(recurrences > max_recurrences)) {
4923+
zend_string *func = get_active_function_or_method_name();
4924+
zend_throw_exception_ex(date_ce_date_malformed_string_exception, 0, "%s(): Recurrence count must be greater or equal to 1 and lower than " ZEND_LONG_FMT " (including options)", ZSTR_VAL(func), max_recurrences + 1);
4925+
zend_string_release(func);
4926+
return false;
4927+
}
4928+
4929+
dpobj->recurrences = (int)recurrences;
49194930

49204931
dpobj->initialized = 1;
49214932

ext/date/tests/DatePeriod_wrong_recurrence_on_constructor.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,6 @@ try {
1515
}
1616

1717
?>
18-
--EXPECT--
19-
DatePeriod::__construct(): Recurrence count must be greater than 0
20-
DatePeriod::__construct(): Recurrence count must be greater than 0
18+
--EXPECTF--
19+
DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d
20+
DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d

ext/date/tests/date_period_bad_iso_format.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,10 @@ try {
4040
}
4141

4242
?>
43-
--EXPECT--
43+
--EXPECTF--
4444
DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain a start date, "R4" given
4545
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain a start date, "R4" given
4646
DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given
4747
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given
48-
DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater than 0
49-
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): Recurrence count must be greater than 0
48+
DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d
49+
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): Recurrence count must be greater or equal to 1 and lower than %d

ext/date/tests/gh14709.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Bug GH-14709 overflow on reccurences parameter
3+
--FILE--
4+
<?php
5+
$start = new DateTime('2018-12-31 00:00:00');
6+
$interval = new DateInterval('P1M');
7+
8+
try {
9+
new DatePeriod($start, $interval, 2147483640);
10+
} catch (Exception $e) {
11+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
12+
}
13+
14+
try {
15+
new DatePeriod($start, $interval, 2147483639, DatePeriod::EXCLUDE_START_DATE | DatePeriod::INCLUDE_END_DATE);
16+
} catch (Exception $e) {
17+
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
18+
}
19+
?>
20+
--EXPECTF--
21+
DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d
22+
DateMalformedStringException: DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d (including options)

0 commit comments

Comments
 (0)