Skip to content

Commit 7b999fb

Browse files
committed
Fix GH-14709 overflow on recurrences for DatePeriod::__construct
1 parent e7af08d commit 7b999fb

File tree

3 files changed

+41
-7
lines changed

3 files changed

+41
-7
lines changed

ext/date/php_date.c

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4903,19 +4903,31 @@ 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(NULL, 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
}
49124914

4915+
49134916
/* options */
49144917
dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
49154918
dpobj->include_end_date = options & PHP_DATE_PERIOD_INCLUDE_END_DATE;
49164919

4917-
/* recurrrences */
4918-
dpobj->recurrences = recurrences + dpobj->include_start_date + dpobj->include_end_date;
4920+
/* recurrences */
4921+
recurrences += dpobj->include_start_date + dpobj->include_end_date;
4922+
4923+
if (UNEXPECTED(recurrences > max_recurrences)) {
4924+
zend_string *func = get_active_function_or_method_name();
4925+
zend_throw_exception_ex(NULL, 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);
4926+
zend_string_release(func);
4927+
return false;
4928+
}
4929+
4930+
dpobj->recurrences = (int)recurrences;
49194931

49204932
dpobj->initialized = 1;
49214933

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/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->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->getMessage();
18+
}
19+
?>
20+
--EXPECTF--
21+
DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d
22+
DatePeriod::__construct(): Recurrence count must be greater or equal to 1 and lower than %d (including options)

0 commit comments

Comments
 (0)