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-- + +--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-- + ['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; }