Skip to content

Commit 06357db

Browse files
committed
Fix Exception constructor optimization in #18442
- Property hooks may now throw exceptions, that seem to be forgotten to be handled - The $previous property is private, and it was not accessible from the constructor of a child class
1 parent b64daf9 commit 06357db

File tree

3 files changed

+129
-17
lines changed

3 files changed

+129
-17
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
--TEST--
2+
Exception properties are overridden by property hooks
3+
--FILE--
4+
<?php
5+
class MyException extends Exception
6+
{
7+
private bool $modified = false;
8+
9+
protected $code {
10+
set($value) {
11+
if ($this->modified) {
12+
throw new Exception();
13+
} else {
14+
$this->modified = true;
15+
16+
$this->code = $value;
17+
}
18+
}
19+
}
20+
}
21+
22+
$e = new MyException("foo", 1, new Exception());
23+
24+
try {
25+
$e->__construct("bar", 2, null);
26+
} catch (Exception) {
27+
}
28+
29+
var_dump($e->getMessage());
30+
var_dump($e->getCode());
31+
var_dump($e->getPrevious()::class);
32+
33+
?>
34+
--EXPECTF--
35+
Deprecated: Creation of dynamic property MyException::$trace is deprecated in %s on line %d
36+
string(3) "bar"
37+
int(1)
38+
string(9) "Exception"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
--TEST--
2+
ErrorException properties are overridden by property hooks
3+
--FILE--
4+
<?php
5+
class MyException extends ErrorException
6+
{
7+
private bool $modified = false;
8+
9+
protected $code {
10+
set($value) {
11+
if ($this->modified) {
12+
throw new Exception();
13+
} else {
14+
$this->modified = true;
15+
16+
$this->code = $value;
17+
}
18+
}
19+
}
20+
}
21+
22+
$e = new MyException("foo", 1, E_NOTICE, "file1", 1, new Exception());
23+
24+
try {
25+
$e->__construct("bar", 2, E_WARNING, "file2", 2, null);
26+
} catch (Exception) {
27+
}
28+
29+
var_dump($e->getMessage());
30+
var_dump($e->getCode());
31+
var_dump($e->getSeverity());
32+
var_dump($e->getFile());
33+
var_dump($e->getLine());
34+
var_dump($e->getPrevious()::class);
35+
36+
?>
37+
--EXPECTF--
38+
Deprecated: Creation of dynamic property MyException::$trace is deprecated in %s on line %d
39+
string(3) "bar"
40+
int(1)
41+
int(8)
42+
string(5) "file1"
43+
int(1)
44+
string(9) "Exception"

Zend/zend_exceptions.c

Lines changed: 47 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -265,11 +265,11 @@ ZEND_API void zend_clear_exception(void) /* {{{ */
265265
/* Same as writing to OBJ_PROP_NUM() when there are no hooks,
266266
* but checks the offset is correct when Zend is built in debug mode.
267267
* This is faster than going through the regular property write routine when the offset is known at compile time. */
268-
static void zend_update_property_num_checked(zend_object *object, uint32_t prop_num, zend_string *member, zval *value)
268+
static void zend_update_property_num_checked(zend_class_entry *scope, zend_object *object, uint32_t prop_num, zend_string *member, zval *value)
269269
{
270270
if (UNEXPECTED(object->ce->num_hooked_props > 0)) {
271271
/* Property may have been overridden with a hook. */
272-
zend_update_property_ex(object->ce, object, member, value);
272+
zend_update_property_ex(scope != NULL ? scope : object->ce, object, member, value);
273273
zval_ptr_dtor(value);
274274
return;
275275
}
@@ -302,19 +302,19 @@ static zend_object *zend_default_exception_new(zend_class_entry *class_type) /*
302302
ZVAL_EMPTY_ARRAY(&trace);
303303
}
304304

305-
zend_update_property_num_checked(object, ZEND_EXCEPTION_TRACE_OFF, ZSTR_KNOWN(ZEND_STR_TRACE), &trace);
305+
zend_update_property_num_checked(NULL, object, ZEND_EXCEPTION_TRACE_OFF, ZSTR_KNOWN(ZEND_STR_TRACE), &trace);
306306

307307
if (EXPECTED((class_type != zend_ce_parse_error && class_type != zend_ce_compile_error)
308308
|| !(filename = zend_get_compiled_filename()))) {
309309
ZVAL_STRING(&tmp, zend_get_executed_filename());
310-
zend_update_property_num_checked(object, ZEND_EXCEPTION_FILE_OFF, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
310+
zend_update_property_num_checked(NULL, object, ZEND_EXCEPTION_FILE_OFF, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
311311
ZVAL_LONG(&tmp, zend_get_executed_lineno());
312-
zend_update_property_num_checked(object, ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
312+
zend_update_property_num_checked(NULL, object, ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
313313
} else {
314314
ZVAL_STR_COPY(&tmp, filename);
315-
zend_update_property_num_checked(object, ZEND_EXCEPTION_FILE_OFF, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
315+
zend_update_property_num_checked(NULL, object, ZEND_EXCEPTION_FILE_OFF, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
316316
ZVAL_LONG(&tmp, zend_get_compiled_lineno());
317-
zend_update_property_num_checked(object, ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
317+
zend_update_property_num_checked(NULL, object, ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
318318
}
319319

320320
return object;
@@ -344,17 +344,26 @@ ZEND_METHOD(Exception, __construct)
344344

345345
if (message) {
346346
ZVAL_STR_COPY(&tmp, message);
347-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_MESSAGE_OFF, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
347+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_MESSAGE_OFF, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
348+
if (UNEXPECTED(EG(exception))) {
349+
RETURN_THROWS();
350+
}
348351
}
349352

350353
if (code) {
351354
ZVAL_LONG(&tmp, code);
352-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_CODE_OFF, ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
355+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_CODE_OFF, ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
356+
if (UNEXPECTED(EG(exception))) {
357+
RETURN_THROWS();
358+
}
353359
}
354360

355361
if (previous) {
356362
Z_ADDREF_P(previous);
357-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_PREVIOUS_OFF, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
363+
zend_update_property_num_checked(zend_ce_exception, Z_OBJ_P(object), ZEND_EXCEPTION_PREVIOUS_OFF, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
364+
if (UNEXPECTED(EG(exception))) {
365+
RETURN_THROWS();
366+
}
358367
}
359368
}
360369
/* }}} */
@@ -394,33 +403,54 @@ ZEND_METHOD(ErrorException, __construct)
394403

395404
if (message) {
396405
ZVAL_STR_COPY(&tmp, message);
397-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_MESSAGE_OFF, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
406+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_MESSAGE_OFF, ZSTR_KNOWN(ZEND_STR_MESSAGE), &tmp);
407+
if (UNEXPECTED(EG(exception))) {
408+
RETURN_THROWS();
409+
}
398410
}
399411

400412
if (code) {
401413
ZVAL_LONG(&tmp, code);
402-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_CODE_OFF, ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
414+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_CODE_OFF, ZSTR_KNOWN(ZEND_STR_CODE), &tmp);
415+
if (UNEXPECTED(EG(exception))) {
416+
RETURN_THROWS();
417+
}
403418
}
404419

405420
if (previous) {
406421
Z_ADDREF_P(previous);
407-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_PREVIOUS_OFF, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
422+
zend_update_property_num_checked(zend_ce_exception, Z_OBJ_P(object), ZEND_EXCEPTION_PREVIOUS_OFF, ZSTR_KNOWN(ZEND_STR_PREVIOUS), previous);
423+
if (UNEXPECTED(EG(exception))) {
424+
RETURN_THROWS();
425+
}
408426
}
409427

410428
ZVAL_LONG(&tmp, severity);
411-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_SEVERITY_OFF, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp);
429+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_SEVERITY_OFF, ZSTR_KNOWN(ZEND_STR_SEVERITY), &tmp);
430+
if (UNEXPECTED(EG(exception))) {
431+
RETURN_THROWS();
432+
}
412433

413434
if (filename) {
414435
ZVAL_STR_COPY(&tmp, filename);
415-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_FILE_OFF, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
436+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_FILE_OFF, ZSTR_KNOWN(ZEND_STR_FILE), &tmp);
437+
if (UNEXPECTED(EG(exception))) {
438+
RETURN_THROWS();
439+
}
416440
}
417441

418442
if (!lineno_is_null) {
419443
ZVAL_LONG(&tmp, lineno);
420-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
444+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
445+
if (UNEXPECTED(EG(exception))) {
446+
RETURN_THROWS();
447+
}
421448
} else if (filename) {
422449
ZVAL_LONG(&tmp, 0);
423-
zend_update_property_num_checked(Z_OBJ_P(object), ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
450+
zend_update_property_num_checked(NULL, Z_OBJ_P(object), ZEND_EXCEPTION_LINE_OFF, ZSTR_KNOWN(ZEND_STR_LINE), &tmp);
451+
if (UNEXPECTED(EG(exception))) {
452+
RETURN_THROWS();
453+
}
424454
}
425455
}
426456
/* }}} */

0 commit comments

Comments
 (0)