Commit b50b30c15ea for php.net

commit b50b30c15ea0ba94ab7217dee8e362039600efae
Author: Máté Kocsis <kocsismate@woohoolabs.com>
Date:   Fri Jun 12 22:03:27 2026 +0200

    standard: Fail unserialization when the `C` format is used for classes that are not `Serializable` (#22058)

    Fixes https://github.com/php/php-src/issues/22046

diff --git a/NEWS b/NEWS
index c6fa558db81..ac338190083 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,9 @@ PHP                                                                        NEWS
   . Deprecate specifying a nullable return type for __debugInfo(). (timwolla)
   . Fixed bug GH-22142 (Assertion failure in zendi_try_get_long() on IS_UNDEF).
     (David Carlier)
+  . Fixed bug GH-22046 (The unserialize function can lead to segfault when
+    non-Serializable internal classes are serialized back with the C format).
+    (kocsismate)

 - BCMath:
   . Added NUL-byte validation to BCMath functions. (jorgsowa)
diff --git a/ext/standard/tests/serialize/serialization_objects_009.phpt b/ext/standard/tests/serialize/serialization_objects_009.phpt
index 9485f3ef806..95b85ccd80f 100644
--- a/ext/standard/tests/serialize/serialization_objects_009.phpt
+++ b/ext/standard/tests/serialize/serialization_objects_009.phpt
@@ -8,17 +8,16 @@
 $b = unserialize($ser);

 var_dump($a, $b);
-
 echo "Done";
 ?>
 --EXPECTF--
-Warning: Class __PHP_Incomplete_Class has no unserializer in %sserialization_objects_009.php on line %d
+Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
+
+Warning: unserialize(): Error at offset 11 of 18 bytes in %s on line %d
+
+Warning: Class C has no unserializer in %s 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) {
-}
+Warning: unserialize(): Error at offset 11 of 18 bytes in %s on line %d
+bool(false)
+bool(false)
 Done
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index d5019d94dc0..484cb5aa8fc 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -770,7 +770,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));
-		object_init_ex(rval, ce);
+		return 0;
 	} 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 00000000000..af297905aa3
--- /dev/null
+++ b/ext/uri/tests/gh22046.phpt
@@ -0,0 +1,19 @@
+--TEST--
+GH-22046: The unserialize function can lead to segfault when internal classes are serialized back with the unsupported C format
+--FILE--
+<?php
+
+$payload = 'C:14:"Uri\WhatWg\Url":0:{}';
+unserialize($payload);
+
+$payload = 'C:15:"Uri\Rfc3986\Uri":0:{}';
+unserialize($payload);
+?>
+--EXPECTF--
+Warning: Class Uri\WhatWg\Url has no unserializer in %s on line %d
+
+Warning: unserialize(): Error at offset 25 of 26 bytes in %s on line %d
+
+Warning: Class Uri\Rfc3986\Uri has no unserializer in %s on line %d
+
+Warning: unserialize(): Error at offset 26 of 27 bytes in %s on line %d