From d3fdacb99fab186654bdf2f3adb17d9c628202f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20Andr=C3=A9=20dos=20Santos=20Lopes?= Date: Wed, 28 Sep 2011 14:47:42 +0000 Subject: [PATCH] - Fixed #55798: serialize followed by unserialize with numeric object prop. gives integer prop. --- NEWS | 2 + ext/standard/tests/serialize/bug55798.phpt | 18 +++++ ext/standard/var_unserializer.c | 77 ++++++++++++---------- ext/standard/var_unserializer.re | 15 +++-- 4 files changed, 73 insertions(+), 39 deletions(-) create mode 100644 ext/standard/tests/serialize/bug55798.phpt diff --git a/NEWS b/NEWS index 29577d98e95..3d3b9be2978 100644 --- a/NEWS +++ b/NEWS @@ -3,6 +3,8 @@ PHP NEWS ?? ??? 2011, PHP 5.3.9 - Core: + . Fixed bug #55798 (serialize followed by unserialize with numeric object + prop. gives integer prop). (Gustavo) . Fixed bug #55749 (TOCTOU issue in getenv() on Windows builds). (Pierre) . Fixed bug #55707 (undefined reference to `__sync_fetch_and_add_4' on Linux parisc). (Felipe) diff --git a/ext/standard/tests/serialize/bug55798.phpt b/ext/standard/tests/serialize/bug55798.phpt new file mode 100644 index 00000000000..df8443b1fa9 --- /dev/null +++ b/ext/standard/tests/serialize/bug55798.phpt @@ -0,0 +1,18 @@ +--TEST-- +Bug #55798 (serialize followed by unserialize with numeric object prop. gives integer prop) +--FILE-- +{0} = 'X'; +$a->{1} = 'Y'; +var_dump(serialize($a)); +var_dump($a->{0}); +$b = unserialize(serialize($a)); +var_dump(serialize($b)); +var_dump($b->{0}); +--EXPECT-- +string(51) "O:8:"stdClass":2:{s:1:"0";s:1:"X";s:1:"1";s:1:"Y";}" +string(1) "X" +string(51) "O:8:"stdClass":2:{s:1:"0";s:1:"X";s:1:"1";s:1:"Y";}" +string(1) "X" diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 1c9304890d0..6663ffcb767 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 on Fri Dec 31 23:52:55 2010 */ +/* Generated by re2c 0.13.5 on Wed Sep 28 15:40:15 2011 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -253,7 +253,7 @@ static inline size_t parse_uiv(const unsigned char *p) #define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC -static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements) +static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements, int objprops) { while (elements-- > 0) { zval *key, *data, **old_data; @@ -282,7 +282,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long return 0; } - switch (Z_TYPE_P(key)) { + if (!objprops) { + switch (Z_TYPE_P(key)) { case IS_LONG: if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) { var_push_dtor(var_hash, old_data); @@ -295,6 +296,12 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long } zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); break; + } + } else { + /* object properties should include no integers */ + convert_to_string(key); + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, + sizeof data, NULL); } zval_dtor(key); @@ -362,7 +369,7 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) zval *retval_ptr = NULL; zval fname; - if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements)) { + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) { return 0; } @@ -396,7 +403,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 400 "ext/standard/var_unserializer.c" +#line 407 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -456,9 +463,9 @@ yy2: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 722 "ext/standard/var_unserializer.re" +#line 729 "ext/standard/var_unserializer.re" { return 0; } -#line 462 "ext/standard/var_unserializer.c" +#line 469 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -501,13 +508,13 @@ yy13: goto yy3; yy14: ++YYCURSOR; -#line 716 "ext/standard/var_unserializer.re" +#line 723 "ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 511 "ext/standard/var_unserializer.c" +#line 518 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -537,7 +544,7 @@ yy20: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 599 "ext/standard/var_unserializer.re" +#line 606 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -654,7 +661,7 @@ yy20: return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 658 "ext/standard/var_unserializer.c" +#line 665 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -679,7 +686,7 @@ yy27: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 591 "ext/standard/var_unserializer.re" +#line 598 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -687,7 +694,7 @@ yy27: return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 691 "ext/standard/var_unserializer.c" +#line 698 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -708,7 +715,7 @@ yy34: yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 571 "ext/standard/var_unserializer.re" +#line 578 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -722,13 +729,13 @@ yy34: array_init_size(*rval, elements); - if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements)) { + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) { return 0; } return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 732 "ext/standard/var_unserializer.c" +#line 739 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -749,7 +756,7 @@ yy41: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 542 "ext/standard/var_unserializer.re" +#line 549 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -778,7 +785,7 @@ yy41: ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 782 "ext/standard/var_unserializer.c" +#line 789 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -799,7 +806,7 @@ yy48: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 514 "ext/standard/var_unserializer.re" +#line 521 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -827,7 +834,7 @@ yy48: ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 831 "ext/standard/var_unserializer.c" +#line 838 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -915,7 +922,7 @@ yy61: } yy63: ++YYCURSOR; -#line 504 "ext/standard/var_unserializer.re" +#line 511 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -925,7 +932,7 @@ use_double: ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 929 "ext/standard/var_unserializer.c" +#line 936 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -984,7 +991,7 @@ yy73: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 489 "ext/standard/var_unserializer.re" +#line 496 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -999,7 +1006,7 @@ yy73: return 1; } -#line 1003 "ext/standard/var_unserializer.c" +#line 1010 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1026,7 +1033,7 @@ yy79: if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 462 "ext/standard/var_unserializer.re" +#line 469 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1053,7 +1060,7 @@ yy79: ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1057 "ext/standard/var_unserializer.c" +#line 1064 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1061,24 +1068,24 @@ yy83: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 455 "ext/standard/var_unserializer.re" +#line 462 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1072 "ext/standard/var_unserializer.c" +#line 1079 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 448 "ext/standard/var_unserializer.re" +#line 455 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1082 "ext/standard/var_unserializer.c" +#line 1089 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1101,7 +1108,7 @@ yy91: if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 425 "ext/standard/var_unserializer.re" +#line 432 "ext/standard/var_unserializer.re" { long id; @@ -1124,7 +1131,7 @@ yy91: return 1; } -#line 1128 "ext/standard/var_unserializer.c" +#line 1135 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1147,7 +1154,7 @@ yy97: if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 404 "ext/standard/var_unserializer.re" +#line 411 "ext/standard/var_unserializer.re" { long id; @@ -1168,9 +1175,9 @@ yy97: return 1; } -#line 1172 "ext/standard/var_unserializer.c" +#line 1179 "ext/standard/var_unserializer.c" } -#line 724 "ext/standard/var_unserializer.re" +#line 731 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 87b86c31315..75e2b554590 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -257,7 +257,7 @@ static inline size_t parse_uiv(const unsigned char *p) #define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC -static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements) +static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements, int objprops) { while (elements-- > 0) { zval *key, *data, **old_data; @@ -286,7 +286,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long return 0; } - switch (Z_TYPE_P(key)) { + if (!objprops) { + switch (Z_TYPE_P(key)) { case IS_LONG: if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) { var_push_dtor(var_hash, old_data); @@ -299,6 +300,12 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long } zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); break; + } + } else { + /* object properties should include no integers */ + convert_to_string(key); + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, + sizeof data, NULL); } zval_dtor(key); @@ -366,7 +373,7 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) zval *retval_ptr = NULL; zval fname; - if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements)) { + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) { return 0; } @@ -581,7 +588,7 @@ use_double: array_init_size(*rval, elements); - if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements)) { + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) { return 0; }