Skip to content

Commit c342b92

Browse files
devnexencharmitro
authored andcommitted
Fix phpGH-14709 overflow on recurrences for DatePeriod::__construct
close phpGH-14710
1 parent 60e82b9 commit c342b92

File tree

5 files changed

+46
-14
lines changed

5 files changed

+46
-14
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
@@ -5122,9 +5122,11 @@ static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_en
51225122

51235123
static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, zend_long recurrences)
51245124
{
5125-
if (dpobj->end == NULL && recurrences < 1) {
5125+
const zend_long max_recurrences = (INT_MAX - 8);
5126+
5127+
if (dpobj->end == NULL && (recurrences < 1 || recurrences > max_recurrences)) {
51265128
zend_string *func = get_active_function_or_method_name();
5127-
zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): Recurrence count must be greater than 0", ZSTR_VAL(func));
5129+
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);
51285130
zend_string_release(func);
51295131
return false;
51305132
}
@@ -5133,8 +5135,17 @@ static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, ze
51335135
dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
51345136
dpobj->include_end_date = options & PHP_DATE_PERIOD_INCLUDE_END_DATE;
51355137

5136-
/* recurrrences */
5137-
dpobj->recurrences = recurrences + dpobj->include_start_date + dpobj->include_end_date;
5138+
/* recurrences */
5139+
recurrences += dpobj->include_start_date + dpobj->include_end_date;
5140+
5141+
if (UNEXPECTED(recurrences > max_recurrences)) {
5142+
zend_string *func = get_active_function_or_method_name();
5143+
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);
5144+
zend_string_release(func);
5145+
return false;
5146+
}
5147+
5148+
dpobj->recurrences = (int)recurrences;
51385149

51395150
dpobj->initialized = 1;
51405151

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: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,9 @@ try {
4141

4242
?>
4343
--EXPECTF--
44-
Deprecated: Calling DatePeriod::__construct(string $isostr, int $options = 0) is deprecated, use DatePeriod::createFromISO8601String() instead in %s on line %d
4544
DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain a start date, "R4" given
4645
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain a start date, "R4" given
47-
48-
Deprecated: Calling DatePeriod::__construct(string $isostr, int $options = 0) is deprecated, use DatePeriod::createFromISO8601String() instead in %s on line %d
4946
DateMalformedPeriodStringException: DatePeriod::__construct(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given
5047
DateMalformedPeriodStringException: DatePeriod::createFromISO8601String(): ISO interval must contain an interval, "R4/2012-07-01T00:00:00Z" given
51-
52-
Deprecated: Calling DatePeriod::__construct(string $isostr, int $options = 0) is deprecated, use DatePeriod::createFromISO8601String() instead in %s on line %d
53-
DateMalformedPeriodStringException: DatePeriod::__construct(): Recurrence count must be greater than 0
54-
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)