[php-src] master: Merge branch 'PHP-8.6'
| From: | Máté Kocsis | Date: | Wed, 30 Sep 2026 20:23:55 +0000 |
| Subject: | [php-src] master: Merge branch 'PHP-8.6' | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-141821@lists.php.net to get a copy of this message | ||
Author: Máté Kocsis (kocsismate)
Date: 2026-09-30T22:23:27+02:00
Commit: https://github.com/php/php-src/commit/fe3d1ba04bebb0e670eaf6b6e64151260c225e4d
Raw diff: https://github.com/php/php-src/commit/fe3d1ba04bebb0e670eaf6b6e64151260c225e4d.diff
Merge branch 'PHP-8.6'
* PHP-8.6:
standard: Create incomplete objects again from the
C format (#24020)
Changed paths:
A ext/standard/tests/serialize/incomplete_class_c_format.phpt
A ext/standard/tests/serialize/incomplete_class_c_format_allowed_classes.phpt
M ext/standard/tests/serialize/serialization_objects_009.phpt
M ext/standard/var_unserializer.re
Diff:
diff --git a/ext/standard/tests/serialize/incomplete_class_c_format.phpt
b/ext/standard/tests/serialize/incomplete_class_c_format.phpt
new file mode 100644
index 000000000000..258e76921c4a
--- /dev/null
+++ b/ext/standard/tests/serialize/incomplete_class_c_format.phpt
@@ -0,0 +1,36 @@
+--TEST--
+unserialize() turns C: objects of missing classes into incomplete objects
+--FILE--
+<?php
+
+var_dump(unserialize('a:2:{i:0;C:7:"Missing":4:{abcd}i:1;s:4:"tail";}'));
+
+function callback(string $class): void
+{
+ echo __FUNCTION__, "($class)\n";
+}
+
+ini_set('unserialize_callback_func', 'callback');
+
+var_dump(unserialize('C:7:"Missing":4:{abcd}'));
+?>
+--EXPECTF--
+Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
+array(2) {
+ [0]=>
+ object(__PHP_Incomplete_Class)#%d (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(7) "Missing"
+ }
+ [1]=>
+ string(4) "tail"
+}
+callback(Missing)
+
+Warning: unserialize(): Function callback() hasn't defined the class it was called for in %s
on line %d
+
+Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
+object(__PHP_Incomplete_Class)#%d (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(7) "Missing"
+}
diff --git a/ext/standard/tests/serialize/incomplete_class_c_format_allowed_classes.phpt
b/ext/standard/tests/serialize/incomplete_class_c_format_allowed_classes.phpt
new file mode 100644
index 000000000000..54a68a935ef1
--- /dev/null
+++ b/ext/standard/tests/serialize/incomplete_class_c_format_allowed_classes.phpt
@@ -0,0 +1,63 @@
+--TEST--
+unserialize() with allowed_classes turns C: objects of classes that are not allowed into incomplete
objects
+--FILE--
+<?php
+
+final class Kept
+{
+ public $a = 1;
+}
+
+final class Blocked implements Serializable
+{
+ public function serialize(): string
+ {
+ return '';
+ }
+
+ public function unserialize(string $data): void
+ {
+ echo __METHOD__, "\n";
+ }
+
+ public function __serialize(): array
+ {
+ return [];
+ }
+
+ public function __unserialize(array $data): void
+ {
+ echo __METHOD__, "\n";
+ }
+}
+
+$payload =
'a:4:{i:0;O:4:"Kept":1:{s:1:"a";i:2;}i:1;C:7:"Blocked":4:{abcd}i:2;C:7:"Missing":4:{abcd}i:3;r:4;}';
+
+var_dump(unserialize($payload, ['allowed_classes' => ['Kept']]));
+?>
+--EXPECTF--
+Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
+
+Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
+array(4) {
+ [0]=>
+ object(Kept)#%d (1) {
+ ["a"]=>
+ int(2)
+ }
+ [1]=>
+ object(__PHP_Incomplete_Class)#%d (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(7) "Blocked"
+ }
+ [2]=>
+ object(__PHP_Incomplete_Class)#%d (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(7) "Missing"
+ }
+ [3]=>
+ object(__PHP_Incomplete_Class)#%d (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(7) "Blocked"
+ }
+}
diff --git a/ext/standard/tests/serialize/serialization_objects_009.phpt
b/ext/standard/tests/serialize/serialization_objects_009.phpt
index 95b85ccd80f7..27da8e53ebb4 100644
--- a/ext/standard/tests/serialize/serialization_objects_009.phpt
+++ b/ext/standard/tests/serialize/serialization_objects_009.phpt
@@ -13,11 +13,12 @@ echo "Done";
--EXPECTF--
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: unserialize(): Error at offset 11 of 18 bytes in %s on line %d
-bool(false)
+object(__PHP_Incomplete_Class)#%d (1) {
+ ["__PHP_Incomplete_Class_Name"]=>
+ string(1) "C"
+}
bool(false)
Done
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 0138471aa63e..e10b067c68d8 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -769,7 +769,11 @@ 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));
- return 0;
+ /* __PHP_Incomplete_Class has no internal state, an empty instance is safe. */
+ if (ce != PHP_IC_ENTRY) {
+ return 0;
+ }
+ object_init_ex(rval, ce);
} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data
*)var_hash) != SUCCESS) {
return 0;
}