From b71d2e16e640e1cad33db2ae595d911dd6ffbf5f Mon Sep 17 00:00:00 2001 From: Derick Rethans Date: Wed, 9 Aug 2023 16:06:46 +0100 Subject: [PATCH] Fix GH-11416: Crash with DatePeriod when uninitialised objects are passed in (PHP 8.2+) --- NEWS | 4 ++++ ext/date/php_date.c | 20 ++++++++++++++++ ext/date/tests/bug-gh11416.phpt | 42 +++++++++++++++++++++++++++++++++ 3 files changed, 66 insertions(+) diff --git a/NEWS b/NEWS index d7f8fd5bf2c55..80a72d58cb5c3 100644 --- a/NEWS +++ b/NEWS @@ -8,6 +8,10 @@ PHP NEWS . Fixed bug GH-10964 (Improve man page about the built-in server). (Alexandre Daubois) +- Date: + . Fixed bug GH-11416 (Crash with DatePeriod when uninitialised objects are + passed in). (Derick) + - Core: . Fixed strerror_r detection at configuration time. (Kévin Dunglas) diff --git a/ext/date/php_date.c b/ext/date/php_date.c index b3a58b09b9585..4e1ff217b5c16 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -5312,6 +5312,11 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has if (Z_TYPE_P(ht_entry) == IS_OBJECT && instanceof_function(Z_OBJCE_P(ht_entry), date_ce_interface)) { php_date_obj *date_obj; date_obj = Z_PHPDATE_P(ht_entry); + + if (!date_obj->time) { + return 0; + } + if (period_obj->start != NULL) { timelib_time_dtor(period_obj->start); } @@ -5329,6 +5334,11 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has if (Z_TYPE_P(ht_entry) == IS_OBJECT && instanceof_function(Z_OBJCE_P(ht_entry), date_ce_interface)) { php_date_obj *date_obj; date_obj = Z_PHPDATE_P(ht_entry); + + if (!date_obj->time) { + return 0; + } + if (period_obj->end != NULL) { timelib_time_dtor(period_obj->end); } @@ -5345,6 +5355,11 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has if (Z_TYPE_P(ht_entry) == IS_OBJECT && instanceof_function(Z_OBJCE_P(ht_entry), date_ce_interface)) { php_date_obj *date_obj; date_obj = Z_PHPDATE_P(ht_entry); + + if (!date_obj->time) { + return 0; + } + if (period_obj->current != NULL) { timelib_time_dtor(period_obj->current); } @@ -5361,6 +5376,11 @@ static bool php_date_period_initialize_from_hash(php_period_obj *period_obj, Has if (Z_TYPE_P(ht_entry) == IS_OBJECT && Z_OBJCE_P(ht_entry) == date_ce_interval) { php_interval_obj *interval_obj; interval_obj = Z_PHPINTERVAL_P(ht_entry); + + if (!interval_obj->initialized) { + return 0; + } + if (period_obj->interval != NULL) { timelib_rel_time_dtor(period_obj->interval); } diff --git a/ext/date/tests/bug-gh11416.phpt b/ext/date/tests/bug-gh11416.phpt index f3746fa6ca6d7..aa86116f90efa 100644 --- a/ext/date/tests/bug-gh11416.phpt +++ b/ext/date/tests/bug-gh11416.phpt @@ -5,6 +5,7 @@ date.timezone=UTC --FILE-- newInstanceWithoutConstructor(); try { @@ -20,9 +21,50 @@ try { echo get_class($e), ': ', $e->getMessage(), "\n"; } +$date = (new ReflectionClass(DateTime::class))->newInstanceWithoutConstructor(); +$dateperiod = (new ReflectionClass(DatePeriod::class))->newInstanceWithoutConstructor(); +$dateinterval = (new ReflectionClass(DateInterval::class))->newInstanceWithoutConstructor(); +try { + $dateperiod->__unserialize(['start' => $date]); +} catch (Error $e) { + echo get_class($e), ': ', $e->getMessage(), "\n"; +} + +try { + $dateperiod->__unserialize(['start' => $now, 'end' => $date]); +} catch (Error $e) { + echo get_class($e), ': ', $e->getMessage(), "\n"; +} + +try { + $dateperiod->__unserialize(['start' => $now, 'end' => $now, 'current' => $date]); +} catch (Error $e) { + echo get_class($e), ': ', $e->getMessage(), "\n"; +} + +try { + $dateperiod->__unserialize(['start' => $now, 'end' => $now, 'current' => $now, 'interval' => $dateinterval]); +} catch (Error $e) { + echo get_class($e), ': ', $e->getMessage(), "\n"; +} + +try { + $dateperiod->__unserialize([ + 'start' => $now, 'end' => $now, 'current' => $now, 'interval' => $simpleInterval, + 'recurrences' => 2, 'include_start_date' => true, 'include_end_date' => true, + ]); + echo "DatePeriod::__unserialize: SUCCESS\n"; +} catch (Error $e) { + echo get_class($e), ': ', $e->getMessage(), "\n"; +} echo "OK\n"; ?> --EXPECT-- Error: The DateTimeInterface object has not been correctly initialized by its constructor Error: The DateTimeInterface object has not been correctly initialized by its constructor +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +Error: Invalid serialization data for DatePeriod object +DatePeriod::__unserialize: SUCCESS OK