--- /dev/null
+--TEST--
+Bug #71940 (Unserialize crushes on restore object reference)
+--FILE--
+<?php
+
+class Identity
+{
+ private $role;
+
+ public function __construct($role)
+ {
+ $this->role = $role;
+ }
+}
+
+class Entry implements \Serializable
+{
+ private $identity;
+
+ public function __construct(Identity $identity)
+ {
+ $this->identity = $identity;
+ }
+
+ public function serialize()
+ {
+ return serialize(array($this->identity));
+ }
+
+ public function unserialize($serialized)
+ {
+ list($this->identity) = unserialize($serialized);
+ }
+}
+
+$identity = new Identity('test');
+$identityRef = &$identity;
+
+$entry1 = new Entry($identity);
+$entry2 = new Entry($identityRef);
+
+$serialized = serialize([$entry1, $entry2]);
+print_r(unserialize($serialized));
+
+?>
+--EXPECTF--
+Array
+(
+ [0] => Entry Object
+ (
+ [identity:Entry:private] => Identity Object
+ (
+ [role:Identity:private] => test
+ )
+
+ )
+
+ [1] => Entry Object
+ (
+ [identity:Entry:private] => Identity Object
+ (
+ [role:Identity:private] => test
+ )
+
+ )
+
+)
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy95;
yy3:
-#line 884 "ext/standard/var_unserializer.re"
+#line 886 "ext/standard/var_unserializer.re"
{ return 0; }
#line 580 "ext/standard/var_unserializer.c"
yy4:
goto yy3;
yy14:
++YYCURSOR;
-#line 878 "ext/standard/var_unserializer.re"
+#line 880 "ext/standard/var_unserializer.re"
{
/* this is the case where we have less data than planned */
php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data");
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 733 "ext/standard/var_unserializer.re"
+#line 735 "ext/standard/var_unserializer.re"
{
size_t len, len2, len3, maxlen;
zend_long elements;
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 726 "ext/standard/var_unserializer.re"
+#line 728 "ext/standard/var_unserializer.re"
{
if (!var_hash) return 0;
}
array_init_size(rval, elements);
-//??? we can't convert from packed to hash during unserialization, because
-//??? reference to some zvals might be keept in var_hash (to support references)
if (elements) {
+ /* we can't convert from packed to hash during unserialization, because
+ reference to some zvals might be keept in var_hash (to support references) */
zend_hash_real_init(Z_ARRVAL_P(rval), 0);
}
+ /* We should keep an reference to rval to prevent it from being dtor */
+ var_push_dtor(var_hash, rval);
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) {
return 0;
}
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
-#line 881 "ext/standard/var_unserializer.c"
+#line 883 "ext/standard/var_unserializer.c"
yy39:
yych = *++YYCURSOR;
if (yych == '+') goto yy40;
ZVAL_STR(rval, str);
return 1;
}
-#line 936 "ext/standard/var_unserializer.c"
+#line 938 "ext/standard/var_unserializer.c"
yy46:
yych = *++YYCURSOR;
if (yych == '+') goto yy47;
ZVAL_STRINGL(rval, str, len);
return 1;
}
-#line 989 "ext/standard/var_unserializer.c"
+#line 991 "ext/standard/var_unserializer.c"
yy53:
yych = *++YYCURSOR;
if (yych <= '/') {
ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL));
return 1;
}
-#line 1086 "ext/standard/var_unserializer.c"
+#line 1088 "ext/standard/var_unserializer.c"
yy65:
yych = *++YYCURSOR;
if (yych <= ',') {
return 1;
}
-#line 1161 "ext/standard/var_unserializer.c"
+#line 1163 "ext/standard/var_unserializer.c"
yy76:
yych = *++YYCURSOR;
if (yych == 'N') goto yy73;
ZVAL_LONG(rval, parse_iv(start + 2));
return 1;
}
-#line 1214 "ext/standard/var_unserializer.c"
+#line 1216 "ext/standard/var_unserializer.c"
yy83:
yych = *++YYCURSOR;
if (yych <= '/') goto yy18;
ZVAL_BOOL(rval, parse_iv(start + 2));
return 1;
}
-#line 1228 "ext/standard/var_unserializer.c"
+#line 1230 "ext/standard/var_unserializer.c"
yy87:
++YYCURSOR;
#line 573 "ext/standard/var_unserializer.re"
ZVAL_NULL(rval);
return 1;
}
-#line 1237 "ext/standard/var_unserializer.c"
+#line 1239 "ext/standard/var_unserializer.c"
yy89:
yych = *++YYCURSOR;
if (yych <= ',') {
return 1;
}
-#line 1285 "ext/standard/var_unserializer.c"
+#line 1287 "ext/standard/var_unserializer.c"
yy95:
yych = *++YYCURSOR;
if (yych <= ',') {
return 1;
}
-#line 1334 "ext/standard/var_unserializer.c"
+#line 1336 "ext/standard/var_unserializer.c"
}
-#line 886 "ext/standard/var_unserializer.re"
+#line 888 "ext/standard/var_unserializer.re"
return 0;
}
array_init_size(rval, elements);
-//??? we can't convert from packed to hash during unserialization, because
-//??? reference to some zvals might be keept in var_hash (to support references)
if (elements) {
+ /* we can't convert from packed to hash during unserialization, because
+ reference to some zvals might be keept in var_hash (to support references) */
zend_hash_real_init(Z_ARRVAL_P(rval), 0);
}
+ /* We should keep an reference to rval to prevent it from being dtor */
+ var_push_dtor(var_hash, rval);
if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) {
return 0;
}