Skip to content

Commit f6c0ab6

Browse files
committed
Fix leak when overriding Exception get hooks
1 parent 7774891 commit f6c0ab6

2 files changed

Lines changed: 43 additions & 9 deletions

File tree

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
--TEST--
2+
Overridden Exception get hooks don't leak
3+
--CREDITS--
4+
Saad Fellahi (TarPeg007)
5+
--FILE--
6+
<?php
7+
8+
class E extends Exception {
9+
public string $file { get => $this->file . '!'; }
10+
public $message { get => $this->message . '!'; }
11+
}
12+
13+
$e = new E('Foo');
14+
15+
var_dump($e->getFile());
16+
var_dump($e->getMessage());
17+
echo $e, "\n";
18+
19+
?>
20+
--EXPECTF--
21+
string(%d) "%sexception_hooks_leak.php!"
22+
string(4) "Foo!"
23+
E: Foo! in %s:%d
24+
Stack trace:
25+
#0 {main}

‎Zend/zend_exceptions.c‎

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,15 @@ ZEND_METHOD(ErrorException, __construct)
439439
#define GET_PROPERTY_SILENT(object, id) \
440440
zend_read_property_ex(i_get_exception_base(Z_OBJ_P(object)), Z_OBJ_P(object), ZSTR_KNOWN(id), 1, &rv)
441441

442+
static zend_always_inline zend_string *zval_get_owned_string(zval *op, zval *rv) {
443+
zend_string *result = zval_get_string(op);
444+
if (op == rv) {
445+
zval_ptr_dtor(rv);
446+
}
447+
return result;
448+
}
449+
#define ZVAL_GET_OWNED_STRING(op) (zval_get_owned_string(op, &rv))
450+
442451
/* {{{ Get the file in which the exception occurred */
443452
ZEND_METHOD(Exception, getFile)
444453
{
@@ -447,7 +456,7 @@ ZEND_METHOD(Exception, getFile)
447456
ZEND_PARSE_PARAMETERS_NONE();
448457

449458
prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_FILE);
450-
RETURN_STR(zval_get_string(prop));
459+
RETURN_STR(ZVAL_GET_OWNED_STRING(prop));
451460
}
452461
/* }}} */
453462

@@ -471,7 +480,7 @@ ZEND_METHOD(Exception, getMessage)
471480
ZEND_PARSE_PARAMETERS_NONE();
472481

473482
prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_MESSAGE);
474-
RETURN_STR(zval_get_string(prop));
483+
RETURN_STR(ZVAL_GET_OWNED_STRING(prop));
475484
}
476485
/* }}} */
477486

@@ -698,8 +707,8 @@ ZEND_METHOD(Exception, __toString)
698707

699708
while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), zend_ce_throwable)) {
700709
zend_string *prev_str = str;
701-
zend_string *message = zval_get_string(GET_PROPERTY(exception, ZEND_STR_MESSAGE));
702-
zend_string *file = zval_get_string(GET_PROPERTY(exception, ZEND_STR_FILE));
710+
zend_string *message = ZVAL_GET_OWNED_STRING(GET_PROPERTY(exception, ZEND_STR_MESSAGE));
711+
zend_string *file = ZVAL_GET_OWNED_STRING(GET_PROPERTY(exception, ZEND_STR_FILE));
703712
zend_long line = zval_get_long(GET_PROPERTY(exception, ZEND_STR_LINE));
704713

705714
fci.size = sizeof(fci);
@@ -938,8 +947,8 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severit
938947
ce_exception = ex->ce;
939948
EG(exception) = NULL;
940949
if (ce_exception == zend_ce_parse_error || ce_exception == zend_ce_compile_error) {
941-
zend_string *message = zval_get_string(GET_PROPERTY(&exception, ZEND_STR_MESSAGE));
942-
zend_string *file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
950+
zend_string *message = ZVAL_GET_OWNED_STRING(GET_PROPERTY(&exception, ZEND_STR_MESSAGE));
951+
zend_string *file = ZVAL_GET_OWNED_STRING(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
943952
zend_long line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE));
944953
int type = (ce_exception == zend_ce_parse_error ? E_PARSE : E_COMPILE_ERROR) | E_DONT_BAIL;
945954

@@ -969,7 +978,7 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severit
969978
ZVAL_OBJ(&zv, EG(exception));
970979
/* do the best we can to inform about the inner exception */
971980
if (instanceof_function(ce_exception, zend_ce_exception) || instanceof_function(ce_exception, zend_ce_error)) {
972-
file = zval_get_string(GET_PROPERTY_SILENT(&zv, ZEND_STR_FILE));
981+
file = ZVAL_GET_OWNED_STRING(GET_PROPERTY_SILENT(&zv, ZEND_STR_FILE));
973982
line = zval_get_long(GET_PROPERTY_SILENT(&zv, ZEND_STR_LINE));
974983
}
975984

@@ -982,8 +991,8 @@ ZEND_API ZEND_COLD zend_result zend_exception_error(zend_object *ex, int severit
982991
}
983992
}
984993

985-
str = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_STRING));
986-
file = zval_get_string(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
994+
str = ZVAL_GET_OWNED_STRING(GET_PROPERTY_SILENT(&exception, ZEND_STR_STRING));
995+
file = ZVAL_GET_OWNED_STRING(GET_PROPERTY_SILENT(&exception, ZEND_STR_FILE));
987996
line = zval_get_long(GET_PROPERTY_SILENT(&exception, ZEND_STR_LINE));
988997

989998
zend_error_va(severity | E_DONT_BAIL,

0 commit comments

Comments
 (0)