Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Zend: Implement __unserialize() for Exception/Error #19826

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions Zend/tests/exceptions/exception_error_serialization.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Check exception Error can round trip serialization
--FILE--
<?php

$e1 = new Error("1", 25, null);
$e2 = new Error("2", 42, $e1);

$s = serialize($e2);

$e = unserialize($s);

var_dump($e->getMessage() === $e2->getMessage());
var_dump($e->getCode() === $e2->getCode());
var_dump($e->getFile() === $e2->getFile());
var_dump($e->getLine() === $e2->getLine());
var_dump($e->getTrace() === $e2->getTrace());
var_dump($e->getPrevious()::class === $e2->getPrevious()::class);

?>
--EXPECT--
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
27 changes: 27 additions & 0 deletions Zend/tests/exceptions/exception_serialization.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
--TEST--
Check exceptions can round trip serialization
--FILE--
<?php

$e1 = new Exception("1", 25, null);
$e2 = new Exception("2", 42, $e1);

$s = serialize($e2);

$e = unserialize($s);

var_dump($e->getMessage() === $e2->getMessage());
var_dump($e->getCode() === $e2->getCode());
var_dump($e->getFile() === $e2->getFile());
var_dump($e->getLine() === $e2->getLine());
var_dump($e->getTrace() === $e2->getTrace());
var_dump($e->getPrevious()::class === $e2->getPrevious()::class);

?>
--EXPECT--
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
bool(true)
5 changes: 3 additions & 2 deletions Zend/tests/serialize/bug70121.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ OK
--EXPECTF--
Fatal error: Uncaught TypeError: Cannot assign stdClass to property Exception::$previous of type ?Throwable in %s:%d
Stack trace:
#0 %s(%d): unserialize('O:12:"DateInter...')
#1 {main}
#0 [internal function]: Exception->__unserialize(Array)
#1 %s(%d): unserialize('O:12:"DateInter...')
#2 {main}
thrown in %s on line %d
89 changes: 89 additions & 0 deletions Zend/zend_exceptions.c
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,95 @@ ZEND_METHOD(Exception, __wakeup)
}
/* }}} */

ZEND_METHOD(Exception, __unserialize)
{
HashTable *ht;

if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &ht) == FAILURE) {
RETURN_THROWS();
}

/* Fake strict_types as zend_update_property_ex() would coerce values compared to unserialize() */
EG(current_execute_data)->func->common.fn_flags |= ZEND_ACC_STRICT_TYPES;

zend_string *key = NULL;
zval *tmp;
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, key, tmp) {
if (UNEXPECTED(key == NULL)) {
zend_throw_error(NULL, "Must have a string key");
RETURN_THROWS();
}
if (ZSTR_VAL(key)[0] == '0円') {
if (zend_string_equals_literal(key, "0円*0円message")) {
if (Z_TYPE_P(tmp) != IS_STRING) {
zend_type_error("Cannot assign %s to property %s::$message of type string",
zend_zval_type_name(tmp), ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
RETURN_THROWS();
}
zend_update_property_num_checked(NULL, Z_OBJ_P(ZEND_THIS), ZEND_EXCEPTION_MESSAGE_OFF, ZSTR_KNOWN(ZEND_STR_MESSAGE), tmp);
zval_add_ref(tmp);
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
continue;
}
if (zend_string_equals_literal(key, "0円*0円code")) {
if (Z_TYPE_P(tmp) != IS_LONG) {
zend_type_error("Cannot assign %s to property %s::$code of type int",
zend_zval_type_name(tmp), ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
RETURN_THROWS();
}
zend_update_property_num_checked(NULL, Z_OBJ_P(ZEND_THIS), ZEND_EXCEPTION_CODE_OFF, ZSTR_KNOWN(ZEND_STR_CODE), tmp);
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
continue;
}
if (zend_string_equals_literal(key, "0円Exception0円previous") || zend_string_equals_literal(key, "0円Error0円previous")) {
if (Z_TYPE_P(tmp) != IS_NULL && !instanceof_function(Z_OBJCE_P(tmp), zend_ce_throwable)) {
zend_type_error("Cannot assign %s to property %s::$previous of type ?Throwable",
zend_zval_type_name(tmp), ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
RETURN_THROWS();
}
zend_update_property_num_checked(NULL, Z_OBJ_P(ZEND_THIS), ZEND_EXCEPTION_PREVIOUS_OFF, ZSTR_KNOWN(ZEND_STR_PREVIOUS), tmp);
zval_add_ref(tmp);
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
continue;
}
if (zend_string_equals_literal(key, "0円Exception0円trace") || zend_string_equals_literal(key, "0円Error0円trace")) {
if (Z_TYPE_P(tmp) != IS_ARRAY) {
zend_type_error("Cannot assign %s to property %s::$trace of type array",
zend_zval_type_name(tmp), ZSTR_VAL(Z_OBJCE_P(ZEND_THIS)->name));
RETURN_THROWS();
}
zend_update_property_num_checked(NULL, Z_OBJ_P(ZEND_THIS), ZEND_EXCEPTION_TRACE_OFF, ZSTR_KNOWN(ZEND_STR_TRACE), tmp);
zval_add_ref(tmp);
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
continue;
}
if (zend_string_starts_with_cstr(key, ZEND_STRL("0円*0円"))) {
const char *name = ZSTR_VAL(key) + sizeof("0円*0円")-1;
zend_update_property(NULL, Z_OBJ_P(ZEND_THIS), name, strlen(name), tmp);
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
continue;
}
// TODO: other private props?
} else {
zend_update_property_ex(NULL, Z_OBJ_P(ZEND_THIS), key, tmp);
if (UNEXPECTED(EG(exception))) {
RETURN_THROWS();
}
}
} ZEND_HASH_FOREACH_END();
}
/* }}} */

/* {{{ ErrorException constructor */
ZEND_METHOD(ErrorException, __construct)
{
Expand Down
7 changes: 7 additions & 0 deletions Zend/zend_exceptions.stub.php
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ public function __construct(string $message = "", int $code = 0, ?Throwable $pre
/** @tentative-return-type */
public function __wakeup(): void {}

public function __unserialize(array $data): void {}

final public function getMessage(): string {}

/** @return int */
Expand Down Expand Up @@ -111,6 +113,11 @@ public function __construct(string $message = "", int $code = 0, ?Throwable $pre
*/
public function __wakeup(): void {}

/**
* @implementation-alias Exception::__unserialize
*/
public function __unserialize(array $data): void {}

/** @implementation-alias Exception::getMessage */
final public function getMessage(): string {}

Expand Down
11 changes: 10 additions & 1 deletion Zend/zend_exceptions_arginfo.h
View file Open in desktop

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions ext/soap/tests/bugs/bug73452.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ echo unserialize($data);
--EXPECTF--
Fatal error: Uncaught TypeError: Cannot assign %s to property SoapFault::$faultcode of type ?string in %s:%d
Stack trace:
#0 %sbug73452.php(4): unserialize('O:9:"SoapFault"...')
#1 {main}
#0 [internal function]: Exception->__unserialize(Array)
#1 %s(4): unserialize('O:9:"SoapFault"...')
#2 {main}
thrown in %s on line %d
30 changes: 20 additions & 10 deletions ext/standard/tests/serialize/bug69152.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,25 @@
Bug #69152: Type Confusion Infoleak Vulnerability in unserialize()
--FILE--
<?php
$x = unserialize('O:9:"exception":1:{s:16:"'."0円".'Exception'."0円".'trace";s:4:"ryat";}');
echo $x;
$x = unserialize('O:4:"test":1:{s:27:"__PHP_Incomplete_Class_Name";R:1;}');
$x->test();
try {
$x = unserialize('O:9:"exception":1:{s:16:"'."0円".'Exception'."0円".'trace";s:4:"ryat";}');
var_dump($x);
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
try {
$x = unserialize('O:4:"test":1:{s:27:"__PHP_Incomplete_Class_Name";R:1;}');
var_dump($x);
$x->test();
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}

?>
--EXPECTF--
Fatal error: Uncaught TypeError: Cannot assign string to property Exception::$trace of type array in %s:%d
Stack trace:
#0 %s(%d): unserialize('O:9:"exception"...')
#1 {main}
thrown in %s on line %d
--EXPECT--
TypeError: Cannot assign string to property Exception::$trace of type array
object(__PHP_Incomplete_Class)#1 (1) {
["__PHP_Incomplete_Class_Name"]=>
*RECURSION*
}
Error: The script tried to call a method on an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
18 changes: 9 additions & 9 deletions ext/standard/tests/serialize/bug69793.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
Bug #69793: Remotely triggerable stack exhaustion via recursive method calls
--FILE--
<?php
$e = unserialize('O:9:"Exception":7:{s:17:"'."0円".'Exception'."0円".'string";s:1:"a";s:7:"'."0円".'*'."0円".'code";i:0;s:7:"'."0円".'*'."0円".'file";s:0:"";s:7:"'."0円".'*'."0円".'line";i:1337;s:16:"'."0円".'Exception'."0円".'trace";a:0:{}s:19:"'."0円".'Exception'."0円".'previous";i:10;s:10:"'."0円".'*'."0円".'message";N;}');

var_dump($e."");
try {
$e = unserialize('O:9:"Exception":7:{s:17:"'."0円".'Exception'."0円".'string";s:1:"a";s:7:"'."0円".'*'."0円".'code";i:0;s:7:"'."0円".'*'."0円".'file";s:0:"";s:7:"'."0円".'*'."0円".'line";i:1337;s:16:"'."0円".'Exception'."0円".'trace";a:0:{}s:19:"'."0円".'Exception'."0円".'previous";i:10;s:10:"'."0円".'*'."0円".'message";N;}');
var_dump($e);
var_dump($e."");
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Cannot assign int to property Exception::$previous of type ?Throwable in %s:%d
Stack trace:
#0 %s(%d): unserialize('O:9:"Exception"...')
#1 {main}
thrown in %s on line %d
--EXPECT--
TypeError: Cannot assign null to property Exception::$message of type string
21 changes: 14 additions & 7 deletions ext/standard/tests/serialize/bug70963.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,19 @@
Bug #70963 (Unserialize shows UNKNOW in result)
--FILE--
<?php
var_dump(unserialize('a:2:{i:0;O:9:"exception":1:{s:16:"'."0円".'Exception'."0円".'trace";s:4:"test";}i:1;R:3;}'));
var_dump(unserialize('a:2:{i:0;O:9:"exception":1:{s:16:"'."0円".'Exception'."0円".'trace";s:4:"test";}i:1;r:3;}'));
try {
var_dump(unserialize('a:2:{i:0;O:9:"exception":1:{s:16:"'."0円".'Exception'."0円".'trace";s:4:"test";}i:1;R:3;}'));
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
try {
var_dump(unserialize('a:2:{i:0;O:9:"exception":1:{s:16:"'."0円".'Exception'."0円".'trace";s:4:"test";}i:1;r:3;}'));
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), PHP_EOL;
}
?>
--EXPECTF--
Fatal error: Uncaught TypeError: Cannot assign string to property Exception::$trace of type array in %s:%d
Stack trace:
#0 %s(%d): unserialize('a:2:{i:0;O:9:"e...')
#1 {main}
thrown in %s on line %d
TypeError: Cannot assign string to property Exception::$trace of type array

Warning: unserialize(): Error at offset 72 of 73 bytes in %s on line %d
TypeError: Cannot assign string to property Exception::$trace of type array
12 changes: 10 additions & 2 deletions sapi/cli/tests/005.phpt
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ string(183) "Class [ <internal:Core> class stdClass ] {
}

"
string(2232) "Class [ <internal:Core> class Exception implements Stringable, Throwable ] {
string(2406) "Class [ <internal:Core> class Exception implements Stringable, Throwable ] {

- Constants [0] {
}
Expand All @@ -58,7 +58,7 @@ string(2232) "Class [ <internal:Core> class Exception implements Stringable, Thr
Property [ private ?Throwable $previous = NULL ]
}

- Methods [11] {
- Methods [12] {
Method [ <internal:Core> private method __clone ] {

- Parameters [0] {
Expand All @@ -82,6 +82,14 @@ string(2232) "Class [ <internal:Core> class Exception implements Stringable, Thr
- Tentative return [ void ]
}

Method [ <internal:Core> public method __unserialize ] {

- Parameters [1] {
Parameter #0 [ <required> array $data ]
}
- Return [ void ]
}

Method [ <internal:Core, prototype Throwable> final public method getMessage ] {

- Parameters [0] {
Expand Down
Loading

AltStyle によって変換されたページ (->オリジナル) /