From: Xinchen Hui Date: Thu, 7 Apr 2016 05:56:55 +0000 (+0800) Subject: Fixed bug #71940 (Unserialize crushes on restore object reference) X-Git-Tag: php-7.0.6RC1~24 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7e042224a26282938b866a49ca3d4af1b368c0cc;p=php Fixed bug #71940 (Unserialize crushes on restore object reference) --- diff --git a/NEWS b/NEWS index e3d2d26426..56629821b2 100644 --- a/NEWS +++ b/NEWS @@ -69,6 +69,8 @@ PHP NEWS . Fixed bug #52339 (SPL autoloader breaks class_exists()). (Nikita) - Standard: + . Fixed bug #71940 (Unserialize crushes on restore object reference). + (Laruence) . Fixed bug #71969 (str_replace returns an incorrect resulting array after a foreach by reference). (Laruence) . Fixed bug #71891 (header_register_callback() and diff --git a/ext/standard/tests/serialize/bug71940.phpt b/ext/standard/tests/serialize/bug71940.phpt new file mode 100644 index 0000000000..c391ba6603 --- /dev/null +++ b/ext/standard/tests/serialize/bug71940.phpt @@ -0,0 +1,67 @@ +--TEST-- +Bug #71940 (Unserialize crushes on restore object reference) +--FILE-- +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 + ) + + ) + +) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 443a42cca3..03ba750873 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -574,7 +574,7 @@ yy2: 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: @@ -619,7 +619,7 @@ yy13: 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"); @@ -655,7 +655,7 @@ yy20: 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; @@ -825,7 +825,7 @@ yy27: 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; @@ -865,19 +865,21 @@ yy34: } 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; @@ -932,7 +934,7 @@ yy41: 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; @@ -985,7 +987,7 @@ yy48: 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 <= '/') { @@ -1082,7 +1084,7 @@ use_double: 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 <= ',') { @@ -1157,7 +1159,7 @@ yy73: return 1; } -#line 1161 "ext/standard/var_unserializer.c" +#line 1163 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1210,7 +1212,7 @@ yy79: 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; @@ -1224,7 +1226,7 @@ yy83: 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" @@ -1233,7 +1235,7 @@ yy87: ZVAL_NULL(rval); return 1; } -#line 1237 "ext/standard/var_unserializer.c" +#line 1239 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1281,7 +1283,7 @@ yy91: return 1; } -#line 1285 "ext/standard/var_unserializer.c" +#line 1287 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1330,9 +1332,9 @@ yy97: 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; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index abd1f28fae..02478167f0 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -710,12 +710,14 @@ use_double: } 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; }