diff --git a/ext/date/php_date.c b/ext/date/php_date.c index b5fa67d22c122..ba692027c3577 100644 --- a/ext/date/php_date.c +++ b/ext/date/php_date.c @@ -320,6 +320,7 @@ static void date_throw_uninitialized_error(zend_class_entry *ce) } if (ce_ptr->type != ZEND_INTERNAL_CLASS) { zend_throw_error(date_ce_date_object_error, "Object of type %s not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name)); + return; } zend_throw_error(date_ce_date_object_error, "Object of type %s (inheriting %s) has not been correctly initialized by calling parent::__construct() in its constructor", ZSTR_VAL(ce->name), ZSTR_VAL(ce_ptr->name)); } @@ -3866,6 +3867,7 @@ PHP_METHOD(DateTimeZone, __construct) if (!timezone_initialize(tzobj, ZSTR_VAL(tz), ZSTR_LEN(tz), &exception_message)) { zend_throw_exception_ex(date_ce_date_invalid_timezone_exception, 0, "DateTimeZone::__construct(): %s", exception_message); efree(exception_message); + RETURN_THROWS(); } } /* }}} */ @@ -4423,11 +4425,6 @@ PHP_METHOD(DateInterval, __construct) static void php_date_interval_initialize_from_hash(zval **return_value, php_interval_obj **intobj, HashTable *myht) /* {{{ */ { - /* If ->diff is already set, then we need to free it first */ - if ((*intobj)->diff) { - timelib_rel_time_dtor((*intobj)->diff); - } - /* If we have a date_string, use that instead */ zval *date_str = zend_hash_str_find(myht, "date_string", strlen("date_string")); if (date_str && Z_TYPE_P(date_str) == IS_STRING) { @@ -4442,6 +4439,14 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte Z_STRVAL_P(date_str), err->error_messages[0].position, err->error_messages[0].character ? err->error_messages[0].character : ' ', err->error_messages[0].message); + timelib_time_dtor(time); + timelib_error_container_dtor(err); + return; + } + + /* If ->diff is already set, then we need to free it first */ + if ((*intobj)->diff) { + timelib_rel_time_dtor((*intobj)->diff); } (*intobj)->diff = timelib_rel_time_clone(&time->relative); @@ -4456,6 +4461,11 @@ static void php_date_interval_initialize_from_hash(zval **return_value, php_inte return; } + /* If ->diff is already set, then we need to free it first */ + if ((*intobj)->diff) { + timelib_rel_time_dtor((*intobj)->diff); + } + /* Set new value */ (*intobj)->diff = timelib_rel_time_ctor(); diff --git a/ext/date/tests/date_interval_set_state_error1.phpt b/ext/date/tests/date_interval_set_state_error1.phpt new file mode 100644 index 0000000000000..ee68de8db4666 --- /dev/null +++ b/ext/date/tests/date_interval_set_state_error1.phpt @@ -0,0 +1,68 @@ +--TEST-- +Test that DateInterval::__unserialize() doesn't modify state in case of a date_string format error +--FILE-- +__unserialize( + [ + "date_string" => "wrong", + ] + ); +} catch (Error $e) { + echo $e->getMessage() . "\n"; +} + +var_dump($interval); + +?> +--EXPECTF-- +object(DateInterval)#%d (%d) { + ["y"]=> + int(1) + ["m"]=> + int(0) + ["d"]=> + int(1) + ["h"]=> + int(1) + ["i"]=> + int(1) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) +} +Unknown or bad format (wrong) at position 0 (w) while unserializing: The timezone could not be found in the database +object(DateInterval)#%d (%d) { + ["y"]=> + int(1) + ["m"]=> + int(0) + ["d"]=> + int(1) + ["h"]=> + int(1) + ["i"]=> + int(1) + ["s"]=> + int(0) + ["f"]=> + float(0) + ["invert"]=> + int(0) + ["days"]=> + bool(false) + ["from_string"]=> + bool(false) +}