Skip to content

Commit 55dd394

Browse files
committed
Convert Exception::getMessage() result to string
We specify that the return type of Exception::getMessage() is a string. However, we don't currently ensure this, because Exception::$message is a protected member that can be set to any type. Fix this by performing an explicit type-cast. This also requires a temporary refcount increment in the __toString() object handler, because there is no additional owner of the object, and it may get released prematurely as part of the __toString() call.
1 parent efbe961 commit 55dd394

File tree

3 files changed

+44
-2
lines changed

3 files changed

+44
-2
lines changed
+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
--TEST--
2+
Exception with delayed message computation
3+
--FILE--
4+
<?php
5+
6+
class MyException extends Exception {
7+
public $message;
8+
public $messageCallback;
9+
10+
public function __construct() {
11+
$this->messageCallback = static function() {
12+
return "Foobar";
13+
};
14+
$this->message = new class($this->message, $this->messageCallback) {
15+
private $message;
16+
private $messageCallback;
17+
18+
public function __construct(&$message, &$messageCallback)
19+
{
20+
$this->message = &$message;
21+
$this->messageCallback = &$messageCallback;
22+
}
23+
24+
public function __toString(): string
25+
{
26+
$messageCallback = $this->messageCallback;
27+
$this->messageCallback = null;
28+
return $this->message = $messageCallback();
29+
}
30+
};
31+
}
32+
}
33+
34+
throw new MyException;
35+
36+
?>
37+
--EXPECTF--
38+
Fatal error: Uncaught MyException: Foobar in %s:%d
39+
Stack trace:
40+
#0 {main}
41+
thrown in %s on line %d

Zend/zend_exceptions.c

+1-2
Original file line numberDiff line numberDiff line change
@@ -414,8 +414,7 @@ ZEND_METHOD(Exception, getMessage)
414414
ZEND_PARSE_PARAMETERS_NONE();
415415

416416
prop = GET_PROPERTY(ZEND_THIS, ZEND_STR_MESSAGE);
417-
ZVAL_DEREF(prop);
418-
ZVAL_COPY(return_value, prop);
417+
RETURN_STR(zval_get_string(prop));
419418
}
420419
/* }}} */
421420

Zend/zend_object_handlers.c

+2
Original file line numberDiff line numberDiff line change
@@ -1800,7 +1800,9 @@ ZEND_API int zend_std_cast_object_tostring(zend_object *readobj, zval *writeobj,
18001800
zend_class_entry *ce = readobj->ce;
18011801
if (ce->__tostring) {
18021802
zval retval;
1803+
GC_ADDREF(readobj);
18031804
zend_call_method_with_0_params(readobj, ce, &ce->__tostring, "__tostring", &retval);
1805+
zend_object_release(readobj);
18041806
if (EXPECTED(Z_TYPE(retval) == IS_STRING)) {
18051807
ZVAL_COPY_VALUE(writeobj, &retval);
18061808
return SUCCESS;

0 commit comments

Comments
 (0)