From 6ae3767e73380d60a3342cc2d3e2b21f4545cb45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Sun, 31 May 2026 23:30:05 +0200 Subject: [PATCH 1/2] General fix --- .../serialize/serialization_objects_009.phpt | 28 ++++++++++--------- ext/standard/var_unserializer.re | 2 +- ext/uri/tests/gh22046.phpt | 22 +++++++++++++++ 3 files changed, 38 insertions(+), 14 deletions(-) create mode 100644 ext/uri/tests/gh22046.phpt diff --git a/ext/standard/tests/serialize/serialization_objects_009.phpt b/ext/standard/tests/serialize/serialization_objects_009.phpt index 9485f3ef8068..09f6404e624f 100644 --- a/ext/standard/tests/serialize/serialization_objects_009.phpt +++ b/ext/standard/tests/serialize/serialization_objects_009.phpt @@ -3,22 +3,24 @@ Custom unserialization of classes with no custom unserializer. --FILE-- 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 diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index d5019d94dc0c..da6ab7db3d99 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -769,7 +769,7 @@ 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)); + zend_throw_exception_ex(NULL, 0, "Class %s has no unserializer", ZSTR_VAL(ce->name)); object_init_ex(rval, ce); } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) { return 0; diff --git a/ext/uri/tests/gh22046.phpt b/ext/uri/tests/gh22046.phpt new file mode 100644 index 000000000000..9b832b8b65fa --- /dev/null +++ b/ext/uri/tests/gh22046.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-22046: The unserialize function with Uri\WhatWg\Url leads to NULL pointer dereference when object serialized back +--FILE-- +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 From b2cb1e3a20747c3e3284192f8896c94f7a21e9c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1t=C3=A9=20Kocsis?= Date: Mon, 1 Jun 2026 07:26:28 +0200 Subject: [PATCH 2/2] Fixes --- ext/standard/var_unserializer.re | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index da6ab7db3d99..2e886902cee6 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -769,8 +769,8 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) } if (ce->unserialize == NULL) { - zend_throw_exception_ex(NULL, 0, "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; } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) { return 0; }