Skip to content

Commit fe3d1ba

Browse files
committed
Merge branch 'PHP-8.6'
* PHP-8.6: standard: Create incomplete objects again from the `C` format (#24020)
2 parents 0cd95dd + 4bf700e commit fe3d1ba

4 files changed

Lines changed: 108 additions & 4 deletions

File tree

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
unserialize() turns C: objects of missing classes into incomplete objects
3+
--FILE--
4+
<?php
5+
6+
var_dump(unserialize('a:2:{i:0;C:7:"Missing":4:{abcd}i:1;s:4:"tail";}'));
7+
8+
function callback(string $class): void
9+
{
10+
echo __FUNCTION__, "($class)\n";
11+
}
12+
13+
ini_set('unserialize_callback_func', 'callback');
14+
15+
var_dump(unserialize('C:7:"Missing":4:{abcd}'));
16+
?>
17+
--EXPECTF--
18+
Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
19+
array(2) {
20+
[0]=>
21+
object(__PHP_Incomplete_Class)#%d (1) {
22+
["__PHP_Incomplete_Class_Name"]=>
23+
string(7) "Missing"
24+
}
25+
[1]=>
26+
string(4) "tail"
27+
}
28+
callback(Missing)
29+
30+
Warning: unserialize(): Function callback() hasn't defined the class it was called for in %s on line %d
31+
32+
Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
33+
object(__PHP_Incomplete_Class)#%d (1) {
34+
["__PHP_Incomplete_Class_Name"]=>
35+
string(7) "Missing"
36+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
--TEST--
2+
unserialize() with allowed_classes turns C: objects of classes that are not allowed into incomplete objects
3+
--FILE--
4+
<?php
5+
6+
final class Kept
7+
{
8+
public $a = 1;
9+
}
10+
11+
final class Blocked implements Serializable
12+
{
13+
public function serialize(): string
14+
{
15+
return '';
16+
}
17+
18+
public function unserialize(string $data): void
19+
{
20+
echo __METHOD__, "\n";
21+
}
22+
23+
public function __serialize(): array
24+
{
25+
return [];
26+
}
27+
28+
public function __unserialize(array $data): void
29+
{
30+
echo __METHOD__, "\n";
31+
}
32+
}
33+
34+
$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;}';
35+
36+
var_dump(unserialize($payload, ['allowed_classes' => ['Kept']]));
37+
?>
38+
--EXPECTF--
39+
Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
40+
41+
Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
42+
array(4) {
43+
[0]=>
44+
object(Kept)#%d (1) {
45+
["a"]=>
46+
int(2)
47+
}
48+
[1]=>
49+
object(__PHP_Incomplete_Class)#%d (1) {
50+
["__PHP_Incomplete_Class_Name"]=>
51+
string(7) "Blocked"
52+
}
53+
[2]=>
54+
object(__PHP_Incomplete_Class)#%d (1) {
55+
["__PHP_Incomplete_Class_Name"]=>
56+
string(7) "Missing"
57+
}
58+
[3]=>
59+
object(__PHP_Incomplete_Class)#%d (1) {
60+
["__PHP_Incomplete_Class_Name"]=>
61+
string(7) "Blocked"
62+
}
63+
}

‎ext/standard/tests/serialize/serialization_objects_009.phpt‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,12 @@ echo "Done";
1313
--EXPECTF--
1414
Warning: Class __PHP_Incomplete_Class has no unserializer in %s on line %d
1515

16-
Warning: unserialize(): Error at offset 11 of 18 bytes in %s on line %d
17-
1816
Warning: Class C has no unserializer in %s on line %d
1917

2018
Warning: unserialize(): Error at offset 11 of 18 bytes in %s on line %d
21-
bool(false)
19+
object(__PHP_Incomplete_Class)#%d (1) {
20+
["__PHP_Incomplete_Class_Name"]=>
21+
string(1) "C"
22+
}
2223
bool(false)
2324
Done

‎ext/standard/var_unserializer.re‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -769,7 +769,11 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce)
769769

770770
if (ce->unserialize == NULL) {
771771
zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name));
772-
return 0;
772+
/* __PHP_Incomplete_Class has no internal state, an empty instance is safe. */
773+
if (ce != PHP_IC_ENTRY) {
774+
return 0;
775+
}
776+
object_init_ex(rval, ce);
773777
} else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) {
774778
return 0;
775779
}

0 commit comments

Comments
 (0)