From: Dmitry Stogov Date: Mon, 17 Mar 2014 13:23:27 +0000 (+0400) Subject: Fixed serialize/unserialize problems X-Git-Tag: POST_PHPNG_MERGE~412^2~291 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=62c448ab8b0f38489af4b9c02061506b65b00c91;p=php Fixed serialize/unserialize problems --- diff --git a/Zend/zend_hash.c b/Zend/zend_hash.c index f06eb7d624..be2b0c742b 100644 --- a/Zend/zend_hash.c +++ b/Zend/zend_hash.c @@ -138,6 +138,13 @@ static void zend_hash_packed_grow(HashTable *ht) HANDLE_UNBLOCK_INTERRUPTIONS(); } +ZEND_API void zend_hash_real_init(HashTable *ht, int packed) +{ + IS_CONSISTENT(ht); + + CHECK_INIT(ht, packed); +} + ZEND_API void zend_hash_packed_to_hash(HashTable *ht) { HANDLE_BLOCK_INTERRUPTIONS(); diff --git a/Zend/zend_hash.h b/Zend/zend_hash.h index 5942611955..2718356497 100644 --- a/Zend/zend_hash.h +++ b/Zend/zend_hash.h @@ -66,7 +66,8 @@ ZEND_API void zend_hash_clean(HashTable *ht); #define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) _zend_hash_init((ht), (nSize), (pDestructor), (persistent) ZEND_FILE_LINE_CC) #define zend_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection) _zend_hash_init_ex((ht), (nSize), (pDestructor), (persistent), (bApplyProtection) ZEND_FILE_LINE_CC) -ZEND_API void zend_hash_packed_to_hash(HashTable *ht); +ZEND_API void zend_hash_real_init(HashTable *ht, int packed); +ZEND_API void zend_hash_packed_to_hash(HashTable *ht); ZEND_API void zend_hash_to_packed(HashTable *ht); /* additions/updates/changes */ diff --git a/ext/standard/var.c b/ext/standard/var.c index c7e5e2fd75..8c2694bef7 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -735,7 +735,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var ZVAL_UNDEF(&var_already); - if (var_hash && + if (var_hash && php_add_var_hash(var_hash, Z_ISREF_P(struc)? Z_REFVAL_P(struc) : struc, &var_already TSRMLS_CC) == FAILURE) { if (Z_ISREF_P(struc)) { smart_str_appendl(buf, "R:", 2); @@ -818,7 +818,6 @@ again: } if (ce && ce != PHP_IC_ENTRY && zend_hash_str_exists(&ce->function_table, "__sleep", sizeof("__sleep")-1)) { -//??? ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1, 0); ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1); BG(serialize_lock)++; res = call_user_function_ex(CG(function_table), struc, &fname, &retval, 0, 0, 1, NULL TSRMLS_CC); @@ -894,7 +893,7 @@ again: /* we should still add element even if it's not OK, * since we already wrote the length of the array before */ if ((data = zend_hash_get_current_data_ex(myht, &pos)) == NULL - || Z_ARR_P(data) == Z_ARR_P(struc) + || (Z_TYPE_P(data) == IS_ARRAY && Z_TYPE_P(struc) == IS_ARRAY && Z_ARR_P(data) == Z_ARR_P(struc)) || (Z_TYPE_P(data) == IS_ARRAY && Z_ARRVAL_P(data)->nApplyCount > 1) ) { smart_str_appendl(buf, "N;", 2); diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 7c39411bff..8e69338b02 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -29,12 +29,12 @@ #define VAR_ENTRIES_DBG 0 typedef struct { - zval data[VAR_ENTRIES_MAX]; + zval *data[VAR_ENTRIES_MAX]; long used_slots; void *next; } var_entries; -static inline zval *var_push(php_unserialize_data_t *var_hashx, zval *rval) +static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval) { var_entries *var_hash = (*var_hashx)->last; #if VAR_ENTRIES_DBG @@ -55,8 +55,7 @@ static inline zval *var_push(php_unserialize_data_t *var_hashx, zval *rval) (*var_hashx)->last = var_hash; } - ZVAL_COPY_VALUE(&var_hash->data[var_hash->used_slots], rval); - return &var_hash->data[var_hash->used_slots++]; + var_hash->data[var_hash->used_slots++] = rval; } PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval) @@ -80,8 +79,8 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval) (*var_hashx)->last_dtor = var_hash; } - ZVAL_COPY(&var_hash->data[var_hash->used_slots], rval); - var_hash->used_slots++; + Z_ADDREF_P(rval); + var_hash->data[var_hash->used_slots++] = rval; } PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval *rval) @@ -105,8 +104,7 @@ PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval *rva (*var_hashx)->last_dtor = var_hash; } - ZVAL_COPY_VALUE(&var_hash->data[var_hash->used_slots], rval); - var_hash->used_slots++; + var_hash->data[var_hash->used_slots++] = rval; } static int var_access(php_unserialize_data_t *var_hashx, long id, zval **store) @@ -125,7 +123,7 @@ static int var_access(php_unserialize_data_t *var_hashx, long id, zval **store) if (id < 0 || id >= var_hash->used_slots) return !SUCCESS; - *store = &var_hash->data[id]; + *store = var_hash->data[id]; return SUCCESS; } @@ -149,7 +147,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { - zval_ptr_dtor(&var_hash->data[i]); + zval_ptr_dtor(var_hash->data[i]); } next = var_hash->next; efree(var_hash); @@ -209,7 +207,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen #define YYMARKER marker -#line 217 "ext/standard/var_unserializer.re" +#line 215 "ext/standard/var_unserializer.re" @@ -277,7 +275,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long while (elements-- > 0) { zval key, *data, d, *old_data; - if (!php_var_unserialize_intern(&key, p, max, NULL TSRMLS_CC)) { + if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { + zval_dtor(&key); return 0; } @@ -286,17 +285,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long return 0; } - if (var_hash && (*p)[0] != 'R') { - data = var_push(var_hash, data); - } else { - data = &d; - } - - ZVAL_UNDEF(data); - if (!php_var_unserialize_intern(data, p, max, var_hash TSRMLS_CC)) { - zval_dtor(&key); - return 0; - } + data = NULL; + ZVAL_UNDEF(&d); if (!objprops) { switch (Z_TYPE(key)) { @@ -304,23 +294,27 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long if ((old_data = zend_hash_index_find(ht, Z_LVAL(key))) != NULL) { var_push_dtor(var_hash, old_data); } - zend_hash_index_update(ht, Z_LVAL(key), data); + data = zend_hash_index_update(ht, Z_LVAL(key), &d); break; case IS_STRING: if ((old_data = zend_symtable_find(ht, Z_STR(key))) != NULL) { var_push_dtor(var_hash, old_data); } - zend_symtable_update(ht, Z_STR(key), data); + data = zend_symtable_update(ht, Z_STR(key), &d); break; } } else { /* object properties should include no integers */ convert_to_string(&key); - zend_hash_update(ht, Z_STR(key), data); + data = zend_hash_update(ht, Z_STR(key), &d); } zval_dtor(&key); + if (!php_var_unserialize(data, p, max, var_hash TSRMLS_CC)) { + return 0; + } + if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; return 0; @@ -390,9 +384,12 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) return 0; } + if (Z_ISREF_P(rval)) { + rval = Z_REFVAL_P(rval); + } + if (Z_OBJCE_P(rval) != PHP_IC_ENTRY && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1)) { -//??? ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0); ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1); BG(serialize_lock)++; call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL TSRMLS_CC); @@ -413,15 +410,6 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) #endif PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -{ - if (var_hash && (*p)[0] != 'R') { - var_push(var_hash, rval); - } - - return php_var_unserialize_intern(UNSERIALIZE_PASSTHRU); -} - -PHPAPI int php_var_unserialize_intern(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref; @@ -433,10 +421,14 @@ PHPAPI int php_var_unserialize_intern(UNSERIALIZE_PARAMETER) return 0; } + if (var_hash && (*p)[0] != 'R') { + var_push(var_hash, rval); + } + start = cursor; -#line 440 "ext/standard/var_unserializer.c" +#line 432 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -496,9 +488,9 @@ yy2: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 777 "ext/standard/var_unserializer.re" +#line 778 "ext/standard/var_unserializer.re" { return 0; } -#line 502 "ext/standard/var_unserializer.c" +#line 494 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -541,13 +533,13 @@ yy13: goto yy3; yy14: ++YYCURSOR; -#line 771 "ext/standard/var_unserializer.re" +#line 772 "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 551 "ext/standard/var_unserializer.c" +#line 543 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -577,7 +569,7 @@ yy20: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 632 "ext/standard/var_unserializer.re" +#line 633 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -716,7 +708,7 @@ yy20: return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 720 "ext/standard/var_unserializer.c" +#line 712 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -741,7 +733,7 @@ yy27: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 624 "ext/standard/var_unserializer.re" +#line 625 "ext/standard/var_unserializer.re" { //??? INIT_PZVAL(rval); @@ -749,7 +741,7 @@ yy27: return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 753 "ext/standard/var_unserializer.c" +#line 745 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -770,7 +762,7 @@ yy34: yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 606 "ext/standard/var_unserializer.re" +#line 604 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -781,6 +773,9 @@ yy34: } array_init_size(rval, elements); +//??? we can't convert from packed to hash during unserialization, becaue +//??? reference to some zvals might be keept in var_hash (to support references) + zend_hash_real_init(Z_ARRVAL_P(rval), 0); if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) { return 0; @@ -788,7 +783,7 @@ yy34: return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 792 "ext/standard/var_unserializer.c" +#line 787 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -809,9 +804,10 @@ yy41: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 577 "ext/standard/var_unserializer.re" +#line 574 "ext/standard/var_unserializer.re" { size_t len, maxlen; +//??? TODO: use zend_string* instead of char* char *str; len = parse_uiv(start + 2); @@ -834,11 +830,11 @@ yy41: YYCURSOR += 2; *p = YYCURSOR; -//??? ZVAL_STRINGL(rval, str, len, 0); ZVAL_STRINGL(rval, str, len); + efree(str); return 1; } -#line 842 "ext/standard/var_unserializer.c" +#line 838 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -859,7 +855,7 @@ yy48: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 550 "ext/standard/var_unserializer.re" +#line 547 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -886,7 +882,7 @@ yy48: ZVAL_STRINGL(rval, str, len); return 1; } -#line 890 "ext/standard/var_unserializer.c" +#line 886 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -974,7 +970,7 @@ yy61: } yy63: ++YYCURSOR; -#line 541 "ext/standard/var_unserializer.re" +#line 538 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -983,7 +979,7 @@ use_double: ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 987 "ext/standard/var_unserializer.c" +#line 983 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1042,7 +1038,7 @@ yy73: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 525 "ext/standard/var_unserializer.re" +#line 522 "ext/standard/var_unserializer.re" { *p = YYCURSOR; @@ -1058,7 +1054,7 @@ yy73: return 1; } -#line 1062 "ext/standard/var_unserializer.c" +#line 1058 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1085,7 +1081,7 @@ yy79: if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 499 "ext/standard/var_unserializer.re" +#line 496 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1111,7 +1107,7 @@ yy79: ZVAL_LONG(rval, parse_iv(start + 2)); return 1; } -#line 1115 "ext/standard/var_unserializer.c" +#line 1111 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1119,22 +1115,22 @@ yy83: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 493 "ext/standard/var_unserializer.re" +#line 490 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_BOOL(rval, parse_iv(start + 2)); return 1; } -#line 1129 "ext/standard/var_unserializer.c" +#line 1125 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 487 "ext/standard/var_unserializer.re" +#line 484 "ext/standard/var_unserializer.re" { *p = YYCURSOR; ZVAL_NULL(rval); return 1; } -#line 1138 "ext/standard/var_unserializer.c" +#line 1134 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1157,7 +1153,7 @@ yy91: if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 464 "ext/standard/var_unserializer.re" +#line 461 "ext/standard/var_unserializer.re" { long id; @@ -1170,7 +1166,7 @@ yy91: } //??? - if (rval == rval_ref) return 0; +//??? if (rval == rval_ref) return 0; if (!ZVAL_IS_UNDEF(rval)) { var_push_dtor_no_addref(var_hash, rval); @@ -1180,7 +1176,7 @@ yy91: return 1; } -#line 1184 "ext/standard/var_unserializer.c" +#line 1180 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1203,7 +1199,7 @@ yy97: if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 444 "ext/standard/var_unserializer.re" +#line 436 "ext/standard/var_unserializer.re" { long id; @@ -1218,14 +1214,19 @@ yy97: if (!ZVAL_IS_UNDEF(rval)) { zval_ptr_dtor(rval); } - ZVAL_COPY(rval, rval_ref); + if (Z_ISREF_P(rval_ref)) { + ZVAL_COPY(rval, rval_ref); + } else { + ZVAL_NEW_REF(rval_ref, rval_ref); + ZVAL_COPY(rval, rval_ref); + } //??? Z_SET_ISREF_PP(rval); return 1; } -#line 1227 "ext/standard/var_unserializer.c" +#line 1228 "ext/standard/var_unserializer.c" } -#line 779 "ext/standard/var_unserializer.re" +#line 780 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 0a89069886..ae195ae88b 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -27,12 +27,12 @@ #define VAR_ENTRIES_DBG 0 typedef struct { - zval data[VAR_ENTRIES_MAX]; + zval *data[VAR_ENTRIES_MAX]; long used_slots; void *next; } var_entries; -static inline zval *var_push(php_unserialize_data_t *var_hashx, zval *rval) +static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval) { var_entries *var_hash = (*var_hashx)->last; #if VAR_ENTRIES_DBG @@ -53,8 +53,7 @@ static inline zval *var_push(php_unserialize_data_t *var_hashx, zval *rval) (*var_hashx)->last = var_hash; } - ZVAL_COPY_VALUE(&var_hash->data[var_hash->used_slots], rval); - return &var_hash->data[var_hash->used_slots++]; + var_hash->data[var_hash->used_slots++] = rval; } PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval) @@ -78,8 +77,8 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval) (*var_hashx)->last_dtor = var_hash; } - ZVAL_COPY(&var_hash->data[var_hash->used_slots], rval); - var_hash->used_slots++; + Z_ADDREF_P(rval); + var_hash->data[var_hash->used_slots++] = rval; } PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval *rval) @@ -103,8 +102,7 @@ PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval *rva (*var_hashx)->last_dtor = var_hash; } - ZVAL_COPY_VALUE(&var_hash->data[var_hash->used_slots], rval); - var_hash->used_slots++; + var_hash->data[var_hash->used_slots++] = rval; } static int var_access(php_unserialize_data_t *var_hashx, long id, zval **store) @@ -123,7 +121,7 @@ static int var_access(php_unserialize_data_t *var_hashx, long id, zval **store) if (id < 0 || id >= var_hash->used_slots) return !SUCCESS; - *store = &var_hash->data[id]; + *store = var_hash->data[id]; return SUCCESS; } @@ -147,7 +145,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { - zval_ptr_dtor(&var_hash->data[i]); + zval_ptr_dtor(var_hash->data[i]); } next = var_hash->next; efree(var_hash); @@ -281,7 +279,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long while (elements-- > 0) { zval key, *data, d, *old_data; - if (!php_var_unserialize_intern(&key, p, max, NULL TSRMLS_CC)) { + if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { + zval_dtor(&key); return 0; } @@ -290,17 +289,8 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long return 0; } - if (var_hash && (*p)[0] != 'R') { - data = var_push(var_hash, data); - } else { - data = &d; - } - - ZVAL_UNDEF(data); - if (!php_var_unserialize_intern(data, p, max, var_hash TSRMLS_CC)) { - zval_dtor(&key); - return 0; - } + data = NULL; + ZVAL_UNDEF(&d); if (!objprops) { switch (Z_TYPE(key)) { @@ -308,23 +298,27 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long if ((old_data = zend_hash_index_find(ht, Z_LVAL(key))) != NULL) { var_push_dtor(var_hash, old_data); } - zend_hash_index_update(ht, Z_LVAL(key), data); + data = zend_hash_index_update(ht, Z_LVAL(key), &d); break; case IS_STRING: if ((old_data = zend_symtable_find(ht, Z_STR(key))) != NULL) { var_push_dtor(var_hash, old_data); } - zend_symtable_update(ht, Z_STR(key), data); + data = zend_symtable_update(ht, Z_STR(key), &d); break; } } else { /* object properties should include no integers */ convert_to_string(&key); - zend_hash_update(ht, Z_STR(key), data); + data = zend_hash_update(ht, Z_STR(key), &d); } zval_dtor(&key); + if (!php_var_unserialize(data, p, max, var_hash TSRMLS_CC)) { + return 0; + } + if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; return 0; @@ -394,9 +388,12 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) return 0; } + if (Z_ISREF_P(rval)) { + rval = Z_REFVAL_P(rval); + } + if (Z_OBJCE_P(rval) != PHP_IC_ENTRY && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1)) { -//??? ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0); ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1); BG(serialize_lock)++; call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL TSRMLS_CC); @@ -417,15 +414,6 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) #endif PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -{ - if (var_hash && (*p)[0] != 'R') { - var_push(var_hash, rval); - } - - return php_var_unserialize_intern(UNSERIALIZE_PASSTHRU); -} - -PHPAPI int php_var_unserialize_intern(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref; @@ -437,6 +425,10 @@ PHPAPI int php_var_unserialize_intern(UNSERIALIZE_PARAMETER) return 0; } + if (var_hash && (*p)[0] != 'R') { + var_push(var_hash, rval); + } + start = cursor; /*!re2c @@ -455,7 +447,12 @@ PHPAPI int php_var_unserialize_intern(UNSERIALIZE_PARAMETER) if (!ZVAL_IS_UNDEF(rval)) { zval_ptr_dtor(rval); } - ZVAL_COPY(rval, rval_ref); + if (Z_ISREF_P(rval_ref)) { + ZVAL_COPY(rval, rval_ref); + } else { + ZVAL_NEW_REF(rval_ref, rval_ref); + ZVAL_COPY(rval, rval_ref); + } //??? Z_SET_ISREF_PP(rval); return 1; @@ -473,7 +470,7 @@ PHPAPI int php_var_unserialize_intern(UNSERIALIZE_PARAMETER) } //??? - if (rval == rval_ref) return 0; +//??? if (rval == rval_ref) return 0; if (!ZVAL_IS_UNDEF(rval)) { var_push_dtor_no_addref(var_hash, rval); @@ -576,6 +573,7 @@ use_double: "S:" uiv ":" ["] { size_t len, maxlen; +//??? TODO: use zend_string* instead of char* char *str; len = parse_uiv(start + 2); @@ -598,8 +596,8 @@ use_double: YYCURSOR += 2; *p = YYCURSOR; -//??? ZVAL_STRINGL(rval, str, len, 0); ZVAL_STRINGL(rval, str, len); + efree(str); return 1; } @@ -613,6 +611,9 @@ use_double: } array_init_size(rval, elements); +//??? we can't convert from packed to hash during unserialization, becaue +//??? reference to some zvals might be keept in var_hash (to support references) + zend_hash_real_init(Z_ARRVAL_P(rval), 0); if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) { return 0;