Skip to content

Commit ad5e182

Browse files
committed
Merge branch 'PHP-8.4' into PHP-8.5
* PHP-8.4: Fix crashes when trying to instantiate uninstantiable classes via date static constructors
2 parents a692381 + ca084ac commit ad5e182

File tree

2 files changed

+112
-10
lines changed

2 files changed

+112
-10
lines changed

ext/date/php_date.c

Lines changed: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1486,7 +1486,8 @@ static void create_date_period_datetime(timelib_time *datetime, zend_class_entry
14861486
if (datetime) {
14871487
php_date_obj *date_obj;
14881488

1489-
object_init_ex(zv, ce);
1489+
zend_result result = object_init_ex(zv, ce);
1490+
ZEND_ASSERT(result == SUCCESS && "should succeed as it reuses an existing object's ce");
14901491
date_obj = Z_PHPDATE_P(zv);
14911492
date_obj->time = timelib_time_clone(datetime);
14921493
} else {
@@ -2318,6 +2319,7 @@ static void add_common_properties(HashTable *myht, zend_object *zobj)
23182319
}
23192320

23202321
/* Advanced Interface */
2322+
/* TODO: remove this API because it is unsafe to use as-is, as it does not propagate the failure/success status. */
23212323
PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
23222324
{
23232325
object_init_ex(object, pce);
@@ -2595,7 +2597,9 @@ PHP_FUNCTION(date_create_from_format)
25952597
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
25962598
ZEND_PARSE_PARAMETERS_END();
25972599

2598-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2600+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2601+
RETURN_THROWS();
2602+
}
25992603
if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) {
26002604
zval_ptr_dtor(return_value);
26012605
RETURN_FALSE;
@@ -2617,7 +2621,9 @@ PHP_FUNCTION(date_create_immutable_from_format)
26172621
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
26182622
ZEND_PARSE_PARAMETERS_END();
26192623

2620-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2624+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2625+
RETURN_THROWS();
2626+
}
26212627
if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) {
26222628
zval_ptr_dtor(return_value);
26232629
RETURN_FALSE;
@@ -2673,7 +2679,9 @@ PHP_METHOD(DateTime, createFromImmutable)
26732679
old_obj = Z_PHPDATE_P(datetimeimmutable_object);
26742680
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeimmutable_object));
26752681

2676-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2682+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2683+
RETURN_THROWS();
2684+
}
26772685
new_obj = Z_PHPDATE_P(return_value);
26782686

26792687
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2694,7 +2702,9 @@ PHP_METHOD(DateTime, createFromInterface)
26942702
old_obj = Z_PHPDATE_P(datetimeinterface_object);
26952703
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object));
26962704

2697-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2705+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2706+
RETURN_THROWS();
2707+
}
26982708
new_obj = Z_PHPDATE_P(return_value);
26992709

27002710
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2712,7 +2722,9 @@ PHP_METHOD(DateTime, createFromTimestamp)
27122722
Z_PARAM_NUMBER(value)
27132723
ZEND_PARSE_PARAMETERS_END();
27142724

2715-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, &new_object);
2725+
if (object_init_ex(&new_object, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2726+
RETURN_THROWS();
2727+
}
27162728
new_dateobj = Z_PHPDATE_P(&new_object);
27172729

27182730
switch (Z_TYPE_P(value)) {
@@ -2748,7 +2760,9 @@ PHP_METHOD(DateTimeImmutable, createFromMutable)
27482760
old_obj = Z_PHPDATE_P(datetime_object);
27492761
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetime_object));
27502762

2751-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2763+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2764+
RETURN_THROWS();
2765+
}
27522766
new_obj = Z_PHPDATE_P(return_value);
27532767

27542768
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2769,7 +2783,9 @@ PHP_METHOD(DateTimeImmutable, createFromInterface)
27692783
old_obj = Z_PHPDATE_P(datetimeinterface_object);
27702784
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object));
27712785

2772-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2786+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2787+
RETURN_THROWS();
2788+
}
27732789
new_obj = Z_PHPDATE_P(return_value);
27742790

27752791
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2787,7 +2803,9 @@ PHP_METHOD(DateTimeImmutable, createFromTimestamp)
27872803
Z_PARAM_NUMBER(value)
27882804
ZEND_PARSE_PARAMETERS_END();
27892805

2790-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, &new_object);
2806+
if (object_init_ex(&new_object, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2807+
RETURN_THROWS();
2808+
}
27912809
new_dateobj = Z_PHPDATE_P(&new_object);
27922810

27932811
switch (Z_TYPE_P(value)) {
@@ -5108,7 +5126,9 @@ PHP_METHOD(DatePeriod, createFromISO8601String)
51085126
Z_PARAM_LONG(options)
51095127
ZEND_PARSE_PARAMETERS_END();
51105128

5111-
object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_period);
5129+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_period) != SUCCESS) {
5130+
RETURN_THROWS();
5131+
}
51125132
dpobj = Z_PHPPERIOD_P(return_value);
51135133

51145134
dpobj->current = NULL;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
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+
MyDateTime::createFromTimestamp(0);
44+
} catch (Error $e) {
45+
echo $e->getMessage(), "\n";
46+
}
47+
48+
try {
49+
MyDateTimeImmutable::createFromFormat('Y-m-d', '2025-01-01');
50+
} catch (Error $e) {
51+
echo $e->getMessage(), "\n";
52+
}
53+
54+
try {
55+
MyDateTimeImmutable::createFromMutable(new DateTime());
56+
} catch (Error $e) {
57+
echo $e->getMessage(), "\n";
58+
}
59+
60+
try {
61+
MyDateTimeImmutable::createFromInterface(new DateTime());
62+
} catch (Error $e) {
63+
echo $e->getMessage(), "\n";
64+
}
65+
66+
try {
67+
MyDateTimeImmutable::createFromTimestamp(0);
68+
} catch (Error $e) {
69+
echo $e->getMessage(), "\n";
70+
}
71+
72+
?>
73+
--EXPECT--
74+
Cannot instantiate abstract class MyDatePeriod
75+
Cannot instantiate abstract class MyDateTime
76+
Cannot instantiate abstract class MyDateTime
77+
Cannot instantiate abstract class MyDateTime
78+
Cannot instantiate abstract class MyDateTime
79+
Cannot instantiate abstract class MyDateTimeImmutable
80+
Cannot instantiate abstract class MyDateTimeImmutable
81+
Cannot instantiate abstract class MyDateTimeImmutable
82+
Cannot instantiate abstract class MyDateTimeImmutable

0 commit comments

Comments
 (0)