Skip to content
Open
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
28 changes: 15 additions & 13 deletions ext/standard/tests/serialize/serialization_objects_009.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@ Custom unserialization of classes with no custom unserializer.
--FILE--
<?php
$ser = 'C:1:"C":6:{dasdas}';
$a = unserialize($ser);

try {
unserialize($ser);
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
}

eval('class C {}');
$b = unserialize($ser);

var_dump($a, $b);
try {
unserialize($ser);
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
}

echo "Done";
?>
--EXPECTF--
Warning: Class __PHP_Incomplete_Class has no unserializer in %sserialization_objects_009.php on line %d

Warning: Class C has no unserializer in %sserialization_objects_009.php on line %d
object(__PHP_Incomplete_Class)#%d (1) {
["__PHP_Incomplete_Class_Name"]=>
string(1) "C"
}
object(C)#%d (0) {
}
--EXPECT--
Exception: Class __PHP_Incomplete_Class has no unserializer
Exception: Class C has no unserializer
Done
4 changes: 2 additions & 2 deletions ext/standard/var_unserializer.re
Original file line number Diff line number Diff line change
Expand Up @@ -769,8 +769,8 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
}

if (ce->unserialize == NULL) {
zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
object_init_ex(rval, ce);
zend_throw_exception_ex(NULL, 0, "Class %s has no unserializer", ZSTR_VAL(ce->name));
return 0;
Comment on lines -772 to +773
Copy link
Copy Markdown
Member

@TimWolla TimWolla Jun 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On a second thought: Just E_WARNING + return 0; should be sufficient here. The error handling in unserialize() is pretty broken, but the return 0; should keep unserialize(…) === false from working, whereas an exception might not.

See also: https://wiki.php.net/rfc/improve_unserialize_error_handling

} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
return 0;
}
Expand Down
22 changes: 22 additions & 0 deletions ext/uri/tests/gh22046.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
GH-22046: The unserialize function with Uri\WhatWg\Url leads to NULL pointer dereference when object serialized back
--FILE--
<?php

$payload = 'C:14:"Uri\WhatWg\Url":0:{}';
try {
unserialize($payload);
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
}

$payload = 'C:15:"Uri\Rfc3986\Uri":0:{}';
try {
unserialize($payload);
} catch (Throwable $e) {
echo $e::class, ": ", $e->getMessage(), PHP_EOL;
}
?>
--EXPECT--
Exception: Class Uri\WhatWg\Url has no unserializer
Exception: Class Uri\Rfc3986\Uri has no unserializer
Loading