Commit f3c50bfb1bc for php.net
commit f3c50bfb1bc032758b1af2e30776abf1a18c866d
Merge: 5df586300ab 2d86f8cf489
Author: Ilija Tovilo <ilija.tovilo@me.com>
Date: Wed Jul 15 20:39:51 2026 +0200
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2:
Fix leak on double DatePeriod::__construct() call
diff --cc NEWS
index 3bebd2660a2,e9e5b76cea6..03a3f4f89f7
--- a/NEWS
+++ b/NEWS
@@@ -1,13 -1,11 +1,15 @@@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
-?? ??? ????, PHP 8.2.33
+?? ??? ????, PHP 8.3.33
+ - Date:
+ . Fixed leak on double DatePeriod::__construct() call. (ilutov)
-02 Jul 2026, PHP 8.2.32
+02 Jul 2026, PHP 8.3.32
+
+- Streams:
+ . Fixed bug GH-21468 (Segfault in file_get_contents w/ a https URL
+ and a proxy set). (CVE-2026-12184) (ndossche)
- OpenSSL:
. Fixed bug GH-22187 (Memory corruption (zend_mm_heap corrupted) in
diff --cc ext/date/php_date.c
index 84fad72948f,c71cef2cf15..a74317bd95c
--- a/ext/date/php_date.c
+++ b/ext/date/php_date.c
@@@ -4883,103 -4720,23 +4883,120 @@@ static bool date_period_initialize(time
return retval;
} /* }}} */
+static bool date_period_init_iso8601_string(php_period_obj *dpobj, zend_class_entry* base_ce, char *isostr, size_t isostr_len, zend_long options, zend_long *recurrences)
+{
+ if (!date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), recurrences, isostr, isostr_len)) {
+ return false;
+ }
+
+ if (dpobj->start == NULL) {
+ zend_string *func = get_active_function_or_method_name();
+ zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr);
+ zend_string_release(func);
+ return false;
+ }
+ if (dpobj->interval == NULL) {
+ zend_string *func = get_active_function_or_method_name();
+ zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr);
+ zend_string_release(func);
+ return false;
+ }
+ if (dpobj->end == NULL && recurrences == 0) {
+ zend_string *func = get_active_function_or_method_name();
+ zend_throw_exception_ex(date_ce_date_malformed_period_string_exception, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr);
+ zend_string_release(func);
+ return false;
+ }
+
+ if (dpobj->start) {
+ timelib_update_ts(dpobj->start, NULL);
+ }
+ if (dpobj->end) {
+ timelib_update_ts(dpobj->end, NULL);
+ }
+ dpobj->start_ce = base_ce;
+
+ return true;
+}
+
+static bool date_period_init_finish(php_period_obj *dpobj, zend_long options, zend_long recurrences)
+{
+ const zend_long max_recurrences = (INT_MAX - 8);
+
+ if (dpobj->end == NULL && (recurrences < 1 || recurrences > max_recurrences)) {
+ zend_string *func = get_active_function_or_method_name();
+ 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);
+ zend_string_release(func);
+ return false;
+ }
+
+ /* options */
+ dpobj->include_start_date = !(options & PHP_DATE_PERIOD_EXCLUDE_START_DATE);
+ dpobj->include_end_date = options & PHP_DATE_PERIOD_INCLUDE_END_DATE;
+
+ /* recurrences */
+ recurrences += dpobj->include_start_date + dpobj->include_end_date;
+
+ if (UNEXPECTED(recurrences > max_recurrences)) {
+ zend_string *func = get_active_function_or_method_name();
+ 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);
+ zend_string_release(func);
+ return false;
+ }
+
+ dpobj->recurrences = (int)recurrences;
+
+ dpobj->initialized = 1;
+
+ initialize_date_period_properties(dpobj);
+
+ return true;
+}
+
+PHP_METHOD(DatePeriod, createFromISO8601String)
+{
+ php_period_obj *dpobj;
+ zend_long recurrences = 0, options = 0;
+ char *isostr = NULL;
+ size_t isostr_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &isostr, &isostr_len, &options) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ if (object_init_ex(return_value, execute_data->This.value.ce ? execute_data->This.value.ce : date_ce_period) != SUCCESS) {
+ RETURN_THROWS();
+ }
+ dpobj = Z_PHPPERIOD_P(return_value);
+
+ dpobj->current = NULL;
+
+ if (!date_period_init_iso8601_string(dpobj, date_ce_immutable, isostr, isostr_len, options, &recurrences)) {
+ RETURN_THROWS();
+ }
+
+ if (!date_period_init_finish(dpobj, options, recurrences)) {
+ RETURN_THROWS();
+ }
+}
+
+ static void date_period_reset(php_period_obj *period_obj)
+ {
+ if (period_obj->start) {
+ timelib_time_dtor(period_obj->start);
+ }
+ if (period_obj->current) {
+ timelib_time_dtor(period_obj->current);
+ }
+ if (period_obj->end) {
+ timelib_time_dtor(period_obj->end);
+ }
+ if (period_obj->interval) {
+ timelib_rel_time_dtor(period_obj->interval);
+ }
+ memset(period_obj, 0, XtOffsetOf(php_period_obj, std));
+ }
+
/* {{{ Creates new DatePeriod object. */
PHP_METHOD(DatePeriod, __construct)
{
@@@ -5001,18 -4758,46 +5018,19 @@@
}
dpobj = Z_PHPPERIOD_P(ZEND_THIS);
- dpobj->current = NULL;
+ date_period_reset(dpobj);
if (isostr) {
- if (!date_period_initialize(&(dpobj->start), &(dpobj->end), &(dpobj->interval), &recurrences, isostr, isostr_len)) {
- RETURN_THROWS();
- }
-
- if (dpobj->start == NULL) {
- zend_string *func = get_active_function_or_method_name();
- zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain a start date, \"%s\" given", ZSTR_VAL(func), isostr);
- zend_string_release(func);
- RETURN_THROWS();
- }
- if (dpobj->interval == NULL) {
- zend_string *func = get_active_function_or_method_name();
- zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain an interval, \"%s\" given", ZSTR_VAL(func), isostr);
- zend_string_release(func);
+ if (!date_period_init_iso8601_string(dpobj, date_ce_date, isostr, isostr_len, options, &recurrences)) {
RETURN_THROWS();
}
- if (dpobj->end == NULL && recurrences == 0) {
- zend_string *func = get_active_function_or_method_name();
- zend_throw_exception_ex(NULL, 0, "%s(): ISO interval must contain an end date or a recurrence count, \"%s\" given", ZSTR_VAL(func), isostr);
- zend_string_release(func);
- RETURN_THROWS();
- }
-
- if (dpobj->start) {
- timelib_update_ts(dpobj->start, NULL);
- }
- if (dpobj->end) {
- timelib_update_ts(dpobj->end, NULL);
- }
- dpobj->start_ce = date_ce_date;
} else {
/* check initialisation */
- DATE_CHECK_INITIALIZED(Z_PHPDATE_P(start)->time, DateTimeInterface);
+ DATE_CHECK_INITIALIZED(Z_PHPDATE_P(start)->time, date_ce_interface);
if (end) {
- DATE_CHECK_INITIALIZED(Z_PHPDATE_P(end)->time, DateTimeInterface);
+ DATE_CHECK_INITIALIZED(Z_PHPDATE_P(end)->time, date_ce_interface);
}
+ DATE_CHECK_INITIALIZED(Z_PHPINTERVAL_P(interval)->initialized, Z_OBJCE_P(interval));
/* init */
php_interval_obj *intobj = Z_PHPINTERVAL_P(interval);