Skip to content

Commit d3a4b4b

Browse files
committed
Fix crashes when trying to instantiate uninstantiable classes via date static constructors
Closes GH-20361.
1 parent b8fbf20 commit d3a4b4b

File tree

3 files changed

+96
-8
lines changed

3 files changed

+96
-8
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.3.29
44

5+
- Date:
6+
. Fix crashes when trying to instantiate uninstantiable classes via date
7+
static constructors. (ndossche)
8+
59
- Opcache:
610
. Fixed bug GH-20329 (opcache.file_cache broken with full interned string
711
buffer). (Arnaud)

ext/date/php_date.c

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1476,7 +1476,8 @@ static void create_date_period_datetime(timelib_time *datetime, zend_class_entry
14761476
if (datetime) {
14771477
php_date_obj *date_obj;
14781478

1479-
object_init_ex(zv, ce);
1479+
zend_result result = object_init_ex(zv, ce);
1480+
ZEND_ASSERT(result == SUCCESS && "should succeed as it reuses an existing object's ce");
14801481
date_obj = Z_PHPDATE_P(zv);
14811482
date_obj->time = timelib_time_clone(datetime);
14821483
} else {
@@ -2345,6 +2346,7 @@ static void add_common_properties(HashTable *myht, zend_object *zobj)
23452346
}
23462347

23472348
/* Advanced Interface */
2349+
/* TODO: remove this API because it is unsafe to use as-is, as it does not propagate the failure/success status. */
23482350
PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
23492351
{
23502352
object_init_ex(object, pce);
@@ -2564,7 +2566,9 @@ PHP_FUNCTION(date_create_from_format)
25642566
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
25652567
ZEND_PARSE_PARAMETERS_END();
25662568

2567-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2569+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2570+
RETURN_THROWS();
2571+
}
25682572
if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) {
25692573
zval_ptr_dtor(return_value);
25702574
RETURN_FALSE;
@@ -2586,7 +2590,9 @@ PHP_FUNCTION(date_create_immutable_from_format)
25862590
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
25872591
ZEND_PARSE_PARAMETERS_END();
25882592

2589-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2593+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2594+
RETURN_THROWS();
2595+
}
25902596
if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) {
25912597
zval_ptr_dtor(return_value);
25922598
RETURN_FALSE;
@@ -2642,7 +2648,9 @@ PHP_METHOD(DateTime, createFromImmutable)
26422648
old_obj = Z_PHPDATE_P(datetimeimmutable_object);
26432649
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeimmutable_object));
26442650

2645-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2651+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2652+
RETURN_THROWS();
2653+
}
26462654
new_obj = Z_PHPDATE_P(return_value);
26472655

26482656
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2663,7 +2671,9 @@ PHP_METHOD(DateTime, createFromInterface)
26632671
old_obj = Z_PHPDATE_P(datetimeinterface_object);
26642672
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object));
26652673

2666-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2674+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2675+
RETURN_THROWS();
2676+
}
26672677
new_obj = Z_PHPDATE_P(return_value);
26682678

26692679
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2684,7 +2694,9 @@ PHP_METHOD(DateTimeImmutable, createFromMutable)
26842694
old_obj = Z_PHPDATE_P(datetime_object);
26852695
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetime_object));
26862696

2687-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2697+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2698+
RETURN_THROWS();
2699+
}
26882700
new_obj = Z_PHPDATE_P(return_value);
26892701

26902702
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2705,7 +2717,9 @@ PHP_METHOD(DateTimeImmutable, createFromInterface)
27052717
old_obj = Z_PHPDATE_P(datetimeinterface_object);
27062718
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object));
27072719

2708-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2720+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2721+
RETURN_THROWS();
2722+
}
27092723
new_obj = Z_PHPDATE_P(return_value);
27102724

27112725
new_obj->time = timelib_time_clone(old_obj->time);
@@ -4950,7 +4964,9 @@ PHP_METHOD(DatePeriod, createFromISO8601String)
49504964
RETURN_THROWS();
49514965
}
49524966

4953-
object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_period);
4967+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_period) != SUCCESS) {
4968+
RETURN_THROWS();
4969+
}
49544970
dpobj = Z_PHPPERIOD_P(return_value);
49554971

49564972
dpobj->current = NULL;
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
--TEST--
2+
Instantiating uninstantiable classes via static constructors
3+
--FILE--
4+
<?php
5+
6+
abstract class MyDatePeriod extends DatePeriod {
7+
public abstract function foo();
8+
}
9+
10+
abstract class MyDateTime extends DateTime {
11+
public abstract function foo();
12+
}
13+
14+
abstract class MyDateTimeImmutable extends DateTimeImmutable {
15+
public abstract function foo();
16+
}
17+
18+
try {
19+
MyDatePeriod::createFromISO8601String('R5');
20+
} catch (Error $e) {
21+
echo $e->getMessage(), "\n";
22+
}
23+
24+
try {
25+
MyDateTime::createFromFormat('Y-m-d', '2025-01-01');
26+
} catch (Error $e) {
27+
echo $e->getMessage(), "\n";
28+
}
29+
30+
try {
31+
MyDateTime::createFromImmutable(new DateTimeImmutable());
32+
} catch (Error $e) {
33+
echo $e->getMessage(), "\n";
34+
}
35+
36+
try {
37+
MyDateTime::createFromInterface(new DateTimeImmutable());
38+
} catch (Error $e) {
39+
echo $e->getMessage(), "\n";
40+
}
41+
42+
try {
43+
MyDateTimeImmutable::createFromFormat('Y-m-d', '2025-01-01');
44+
} catch (Error $e) {
45+
echo $e->getMessage(), "\n";
46+
}
47+
48+
try {
49+
MyDateTimeImmutable::createFromMutable(new DateTime());
50+
} catch (Error $e) {
51+
echo $e->getMessage(), "\n";
52+
}
53+
54+
try {
55+
MyDateTimeImmutable::createFromInterface(new DateTime());
56+
} catch (Error $e) {
57+
echo $e->getMessage(), "\n";
58+
}
59+
60+
?>
61+
--EXPECT--
62+
Cannot instantiate abstract class MyDatePeriod
63+
Cannot instantiate abstract class MyDateTime
64+
Cannot instantiate abstract class MyDateTime
65+
Cannot instantiate abstract class MyDateTime
66+
Cannot instantiate abstract class MyDateTimeImmutable
67+
Cannot instantiate abstract class MyDateTimeImmutable
68+
Cannot instantiate abstract class MyDateTimeImmutable

0 commit comments

Comments
 (0)