Skip to content

Commit ca084ac

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

File tree

3 files changed

+116
-10
lines changed

3 files changed

+116
-10
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.4.16
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: 30 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,7 +1483,8 @@ static void create_date_period_datetime(timelib_time *datetime, zend_class_entry
14831483
if (datetime) {
14841484
php_date_obj *date_obj;
14851485

1486-
object_init_ex(zv, ce);
1486+
zend_result result = object_init_ex(zv, ce);
1487+
ZEND_ASSERT(result == SUCCESS && "should succeed as it reuses an existing object's ce");
14871488
date_obj = Z_PHPDATE_P(zv);
14881489
date_obj->time = timelib_time_clone(datetime);
14891490
} else {
@@ -2354,6 +2355,7 @@ static void add_common_properties(HashTable *myht, zend_object *zobj)
23542355
}
23552356

23562357
/* Advanced Interface */
2358+
/* TODO: remove this API because it is unsafe to use as-is, as it does not propagate the failure/success status. */
23572359
PHPAPI zval *php_date_instantiate(zend_class_entry *pce, zval *object) /* {{{ */
23582360
{
23592361
object_init_ex(object, pce);
@@ -2631,7 +2633,9 @@ PHP_FUNCTION(date_create_from_format)
26312633
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
26322634
ZEND_PARSE_PARAMETERS_END();
26332635

2634-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2636+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2637+
RETURN_THROWS();
2638+
}
26352639
if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) {
26362640
zval_ptr_dtor(return_value);
26372641
RETURN_FALSE;
@@ -2653,7 +2657,9 @@ PHP_FUNCTION(date_create_immutable_from_format)
26532657
Z_PARAM_OBJECT_OF_CLASS_OR_NULL(timezone_object, date_ce_timezone)
26542658
ZEND_PARSE_PARAMETERS_END();
26552659

2656-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2660+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2661+
RETURN_THROWS();
2662+
}
26572663
if (!php_date_initialize(Z_PHPDATE_P(return_value), time_str, time_str_len, format_str, timezone_object, PHP_DATE_INIT_FORMAT)) {
26582664
zval_ptr_dtor(return_value);
26592665
RETURN_FALSE;
@@ -2709,7 +2715,9 @@ PHP_METHOD(DateTime, createFromImmutable)
27092715
old_obj = Z_PHPDATE_P(datetimeimmutable_object);
27102716
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeimmutable_object));
27112717

2712-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2718+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2719+
RETURN_THROWS();
2720+
}
27132721
new_obj = Z_PHPDATE_P(return_value);
27142722

27152723
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2730,7 +2738,9 @@ PHP_METHOD(DateTime, createFromInterface)
27302738
old_obj = Z_PHPDATE_P(datetimeinterface_object);
27312739
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object));
27322740

2733-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, return_value);
2741+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2742+
RETURN_THROWS();
2743+
}
27342744
new_obj = Z_PHPDATE_P(return_value);
27352745

27362746
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2748,7 +2758,9 @@ PHP_METHOD(DateTime, createFromTimestamp)
27482758
Z_PARAM_NUMBER(value)
27492759
ZEND_PARSE_PARAMETERS_END();
27502760

2751-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date, &new_object);
2761+
if (object_init_ex(&new_object, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_date) != SUCCESS) {
2762+
RETURN_THROWS();
2763+
}
27522764
new_dateobj = Z_PHPDATE_P(&new_object);
27532765

27542766
switch (Z_TYPE_P(value)) {
@@ -2784,7 +2796,9 @@ PHP_METHOD(DateTimeImmutable, createFromMutable)
27842796
old_obj = Z_PHPDATE_P(datetime_object);
27852797
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetime_object));
27862798

2787-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2799+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2800+
RETURN_THROWS();
2801+
}
27882802
new_obj = Z_PHPDATE_P(return_value);
27892803

27902804
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2805,7 +2819,9 @@ PHP_METHOD(DateTimeImmutable, createFromInterface)
28052819
old_obj = Z_PHPDATE_P(datetimeinterface_object);
28062820
DATE_CHECK_INITIALIZED(old_obj->time, Z_OBJCE_P(datetimeinterface_object));
28072821

2808-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, return_value);
2822+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2823+
RETURN_THROWS();
2824+
}
28092825
new_obj = Z_PHPDATE_P(return_value);
28102826

28112827
new_obj->time = timelib_time_clone(old_obj->time);
@@ -2823,7 +2839,9 @@ PHP_METHOD(DateTimeImmutable, createFromTimestamp)
28232839
Z_PARAM_NUMBER(value)
28242840
ZEND_PARSE_PARAMETERS_END();
28252841

2826-
php_date_instantiate(execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable, &new_object);
2842+
if (object_init_ex(&new_object, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_immutable) != SUCCESS) {
2843+
RETURN_THROWS();
2844+
}
28272845
new_dateobj = Z_PHPDATE_P(&new_object);
28282846

28292847
switch (Z_TYPE_P(value)) {
@@ -5171,7 +5189,9 @@ PHP_METHOD(DatePeriod, createFromISO8601String)
51715189
Z_PARAM_LONG(options)
51725190
ZEND_PARSE_PARAMETERS_END();
51735191

5174-
object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_period);
5192+
if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_period) != SUCCESS) {
5193+
RETURN_THROWS();
5194+
}
51755195
dpobj = Z_PHPPERIOD_P(return_value);
51765196

51775197
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)