diff options
Diffstat (limited to 'ext/standard/var_unserializer.c')
| -rw-r--r-- | ext/standard/var_unserializer.c | 621 |
1 files changed, 340 insertions, 281 deletions
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 79d98e5a24..cb5d8662d6 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -2,7 +2,7 @@ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ - | PHP Version 5 | + | PHP Version 7 | +----------------------------------------------------------------------+ | Copyright (c) 1997-2016 The PHP Group | +----------------------------------------------------------------------+ @@ -30,15 +30,21 @@ typedef struct { zval *data[VAR_ENTRIES_MAX]; - long used_slots; + zend_long used_slots; void *next; } var_entries; -static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval) +typedef struct { + zval data[VAR_ENTRIES_MAX]; + zend_long used_slots; + void *next; +} var_dtor_entries; + +static inline void var_push(php_unserialize_data_t *var_hashx, zval *rval) { var_entries *var_hash = (*var_hashx)->last; #if VAR_ENTRIES_DBG - fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval)); + fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(rval)); #endif if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { @@ -55,82 +61,56 @@ static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval) (*var_hashx)->last = var_hash; } - var_hash->data[var_hash->used_slots++] = *rval; + var_hash->data[var_hash->used_slots++] = rval; } -PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval) +PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval *rval) { - var_entries *var_hash; - - if (!var_hashx || !*var_hashx) { - return; - } - - var_hash = (*var_hashx)->last_dtor; -#if VAR_ENTRIES_DBG - fprintf(stderr, "var_push_dtor(%p, %ld): %d\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval)); -#endif - - if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { - var_hash = emalloc(sizeof(var_entries)); - var_hash->used_slots = 0; - var_hash->next = 0; - - if (!(*var_hashx)->first_dtor) { - (*var_hashx)->first_dtor = var_hash; - } else { - ((var_entries *) (*var_hashx)->last_dtor)->next = var_hash; - } - - (*var_hashx)->last_dtor = var_hash; - } - - Z_ADDREF_PP(rval); - var_hash->data[var_hash->used_slots++] = *rval; + zval *tmp_var = var_tmp_var(var_hashx); + if (!tmp_var) { + return; + } + ZVAL_COPY(tmp_var, rval); } -PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval) +PHPAPI zval *var_tmp_var(php_unserialize_data_t *var_hashx) { - var_entries *var_hash; + var_dtor_entries *var_hash; if (!var_hashx || !*var_hashx) { - return; + return NULL; } var_hash = (*var_hashx)->last_dtor; -#if VAR_ENTRIES_DBG - fprintf(stderr, "var_push_dtor_no_addref(%p, %ld): %d (%d)\n", *rval, var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval)); -#endif - - if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { - var_hash = emalloc(sizeof(var_entries)); - var_hash->used_slots = 0; - var_hash->next = 0; - - if (!(*var_hashx)->first_dtor) { - (*var_hashx)->first_dtor = var_hash; - } else { - ((var_entries *) (*var_hashx)->last_dtor)->next = var_hash; - } - - (*var_hashx)->last_dtor = var_hash; - } - - var_hash->data[var_hash->used_slots++] = *rval; + if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) { + var_hash = emalloc(sizeof(var_dtor_entries)); + var_hash->used_slots = 0; + var_hash->next = 0; + + if (!(*var_hashx)->first_dtor) { + (*var_hashx)->first_dtor = var_hash; + } else { + ((var_dtor_entries *) (*var_hashx)->last_dtor)->next = var_hash; + } + + (*var_hashx)->last_dtor = var_hash; + } + ZVAL_UNDEF(&var_hash->data[var_hash->used_slots]); + return &var_hash->data[var_hash->used_slots++]; } -PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval) +PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval *nzval) { - long i; + zend_long i; var_entries *var_hash = (*var_hashx)->first; #if VAR_ENTRIES_DBG - fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(nzval)); + fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_P(nzval)); #endif while (var_hash) { for (i = 0; i < var_hash->used_slots; i++) { if (var_hash->data[i] == ozval) { - var_hash->data[i] = *nzval; + var_hash->data[i] = nzval; /* do not break here */ } } @@ -138,7 +118,7 @@ PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **n } } -static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store) +static zval *var_access(php_unserialize_data_t *var_hashx, zend_long id) { var_entries *var_hash = (*var_hashx)->first; #if VAR_ENTRIES_DBG @@ -150,65 +130,62 @@ static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store) id -= VAR_ENTRIES_MAX; } - if (!var_hash) return !SUCCESS; + if (!var_hash) return NULL; - if (id < 0 || id >= var_hash->used_slots) return !SUCCESS; + if (id < 0 || id >= var_hash->used_slots) return NULL; - *store = &var_hash->data[id]; - - return SUCCESS; + return var_hash->data[id]; } PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) { void *next; - long i; + zend_long i; var_entries *var_hash = (*var_hashx)->first; + var_dtor_entries *var_dtor_hash = (*var_hashx)->first_dtor; #if VAR_ENTRIES_DBG fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L); #endif while (var_hash) { next = var_hash->next; - efree(var_hash); + efree_size(var_hash, sizeof(var_entries)); var_hash = next; } - var_hash = (*var_hashx)->first_dtor; - - while (var_hash) { - for (i = 0; i < var_hash->used_slots; i++) { + while (var_dtor_hash) { + for (i = 0; i < var_dtor_hash->used_slots; i++) { #if VAR_ENTRIES_DBG - fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_hash->data[i], Z_REFCOUNT_P(var_hash->data[i])); + fprintf(stderr, "var_destroy dtor(%p, %ld)\n", var_dtor_hash->data[i], Z_REFCOUNT_P(var_dtor_hash->data[i])); #endif - zval_ptr_dtor(&var_hash->data[i]); + zval_ptr_dtor(&var_dtor_hash->data[i]); } - next = var_hash->next; - efree(var_hash); - var_hash = next; + next = var_dtor_hash->next; + efree_size(var_dtor_hash, sizeof(var_dtor_entries)); + var_dtor_hash = next; } } /* }}} */ -static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen) +static zend_string *unserialize_str(const unsigned char **p, size_t len, size_t maxlen) { size_t i, j; - char *str = safe_emalloc(*len, 1, 1); + zend_string *str = zend_string_safe_alloc(1, len, 0, 0); unsigned char *end = *(unsigned char **)p+maxlen; if (end < *p) { - efree(str); + zend_string_free(str); return NULL; } - for (i = 0; i < *len; i++) { + for (i = 0; i < len; i++) { if (*p >= end) { - efree(str); + zend_string_free(str); return NULL; } if (**p != '\\') { - str[i] = (char)**p; + ZSTR_VAL(str)[i] = (char)**p; } else { unsigned char ch = 0; @@ -221,19 +198,39 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen } else if (**p >= 'A' && **p <= 'F') { ch = (ch << 4) + (**p -'A'+10); } else { - efree(str); + zend_string_free(str); return NULL; } } - str[i] = (char)ch; + ZSTR_VAL(str)[i] = (char)ch; } (*p)++; } - str[i] = 0; - *len = i; + ZSTR_VAL(str)[i] = 0; + ZSTR_LEN(str) = i; return str; } +static inline int unserialize_allowed_class(zend_string *class_name, HashTable *classes) +{ + zend_string *lcname; + int res; + ALLOCA_FLAG(use_heap) + + if(classes == NULL) { + return 1; + } + if(!zend_hash_num_elements(classes)) { + return 0; + } + + ZSTR_ALLOCA_ALLOC(lcname, ZSTR_LEN(class_name), use_heap); + zend_str_tolower_copy(ZSTR_VAL(lcname), ZSTR_VAL(class_name), ZSTR_LEN(class_name)); + res = zend_hash_exists(classes, lcname); + ZSTR_ALLOCA_FREE(lcname, use_heap); + return res; +} + #define YYFILL(n) do { } while (0) #define YYCTYPE unsigned char #define YYCURSOR cursor @@ -241,15 +238,15 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen #define YYMARKER marker -#line 249 "ext/standard/var_unserializer.re" +#line 246 "ext/standard/var_unserializer.re" -static inline long parse_iv2(const unsigned char *p, const unsigned char **q) +static inline zend_long parse_iv2(const unsigned char *p, const unsigned char **q) { char cursor; - long result = 0; + zend_long result = 0; int neg = 0; switch (*p) { @@ -274,7 +271,7 @@ static inline long parse_iv2(const unsigned char *p, const unsigned char **q) return result; } -static inline long parse_iv(const unsigned char *p) +static inline zend_long parse_iv(const unsigned char *p) { return parse_iv2(p, NULL); } @@ -301,60 +298,91 @@ static inline size_t parse_uiv(const unsigned char *p) return result; } -#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 +#define UNSERIALIZE_PARAMETER zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash, HashTable *classes +#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash, classes -static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, long elements, int objprops) +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER); + +static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { while (elements-- > 0) { - zval *key, *data, **old_data; - - ALLOC_INIT_ZVAL(key); + zval key, *data, d, *old_data; + zend_ulong idx; - if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { - var_push_dtor_no_addref(var_hash, &key); - return 0; - } + ZVAL_UNDEF(&key); - if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { - var_push_dtor_no_addref(var_hash, &key); + if (!php_var_unserialize_internal(&key, p, max, NULL, classes)) { + zval_dtor(&key); return 0; } - ALLOC_INIT_ZVAL(data); - - if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { - var_push_dtor_no_addref(var_hash, &key); - var_push_dtor_no_addref(var_hash, &data); - return 0; - } + data = NULL; + ZVAL_UNDEF(&d); if (!objprops) { - switch (Z_TYPE_P(key)) { - case IS_LONG: - if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) { + if (Z_TYPE(key) == IS_LONG) { + idx = Z_LVAL(key); +numeric_key: + if (UNEXPECTED((old_data = zend_hash_index_find(ht, idx)) != NULL)) { + //??? update hash var_push_dtor(var_hash, old_data); + data = zend_hash_index_update(ht, idx, &d); + } else { + data = zend_hash_index_add_new(ht, idx, &d); } - zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL); - break; - case IS_STRING: - if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) { + } else if (Z_TYPE(key) == IS_STRING) { + if (UNEXPECTED(ZEND_HANDLE_NUMERIC(Z_STR(key), idx))) { + goto numeric_key; + } + if (UNEXPECTED((old_data = zend_hash_find(ht, Z_STR(key))) != NULL)) { + //??? update hash var_push_dtor(var_hash, old_data); + data = zend_hash_update(ht, Z_STR(key), &d); + } else { + data = zend_hash_add_new(ht, Z_STR(key), &d); } - zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); - break; + } else { + zval_dtor(&key); + return 0; } } else { - /* object properties should include no integers */ - convert_to_string(key); - if (zend_hash_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) { - var_push_dtor(var_hash, old_data); + if (EXPECTED(Z_TYPE(key) == IS_STRING)) { +string_key: + if ((old_data = zend_hash_find(ht, Z_STR(key))) != NULL) { + if (Z_TYPE_P(old_data) == IS_INDIRECT) { + old_data = Z_INDIRECT_P(old_data); + } + var_push_dtor(var_hash, old_data); + data = zend_hash_update_ind(ht, Z_STR(key), &d); + } else { + data = zend_hash_add_new(ht, Z_STR(key), &d); + } + } else if (Z_TYPE(key) == IS_LONG) { + /* object properties should include no integers */ + convert_to_string(&key); + goto string_key; + } else { + zval_dtor(&key); + return 0; + } + } + + if (!php_var_unserialize_internal(data, p, max, var_hash, classes)) { + zval_dtor(&key); + return 0; + } + + if (UNEXPECTED(Z_ISUNDEF_P(data))) { + if (Z_TYPE(key) == IS_LONG) { + zend_hash_index_del(ht, Z_LVAL(key)); + } else { + zend_hash_del_ind(ht, Z_STR(key)); } - zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, - sizeof data, NULL); + } else { + var_push_dtor(var_hash, data); } - var_push_dtor(var_hash, &data); - var_push_dtor_no_addref(var_hash, &key); + + zval_dtor(&key); if (elements && *(*p-1) != ';' && *(*p-1) != '}') { (*p)--; @@ -378,21 +406,21 @@ static inline int finish_nested_data(UNSERIALIZE_PARAMETER) static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) { - long datalen; + zend_long datalen; datalen = parse_iv2((*p) + 2, p); (*p) += 2; if (datalen < 0 || (max - (*p)) <= datalen) { - zend_error(E_WARNING, "Insufficient data for unserializing - %ld required, %ld present", datalen, (long)(max - (*p))); + zend_error(E_WARNING, "Insufficient data for unserializing - %pd required, %pd present", datalen, (zend_long)(max - (*p))); return 0; } if (ce->unserialize == NULL) { - zend_error(E_WARNING, "Class %s has no unserializer", ce->name); - object_init_ex(*rval, ce); - } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) != SUCCESS) { + zend_error(E_WARNING, "Class %s has no unserializer", ZSTR_VAL(ce->name)); + object_init_ex(rval, ce); + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash) != SUCCESS) { return 0; } @@ -401,9 +429,9 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) +static inline zend_long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) { - long elements; + zend_long elements; if( *p >= max - 2) { zend_error(E_WARNING, "Bad unserialize data"); @@ -415,7 +443,7 @@ static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) (*p) += 2; if (ce->serialize == NULL) { - object_init_ex(*rval, ce); + object_init_ex(rval, ce); } else { /* If this class implements Serializable, it should not land here but in object_custom(). The passed string obviously doesn't descend from the regular serializer. */ @@ -429,40 +457,40 @@ static inline long object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) #ifdef PHP_WIN32 # pragma optimize("", off) #endif -static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) +static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) { - zval *retval_ptr = NULL; + zval retval; zval fname; + HashTable *ht; + zend_bool has_wakeup; - if (Z_TYPE_PP(rval) != IS_OBJECT) { + if (Z_TYPE_P(rval) != IS_OBJECT) { return 0; } - if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements, 1)) { - /* We've got partially constructed object on our hands here. Wipe it. */ - if(Z_TYPE_PP(rval) == IS_OBJECT) { - zend_hash_clean(Z_OBJPROP_PP(rval)); - zend_object_store_ctor_failed(*rval TSRMLS_CC); - } - ZVAL_NULL(*rval); + has_wakeup = Z_OBJCE_P(rval) != PHP_IC_ENTRY + && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1); + + ht = Z_OBJPROP_P(rval); + zend_hash_extend(ht, zend_hash_num_elements(ht) + elements, (ht->u.flags & HASH_FLAG_PACKED)); + if (!process_nested_data(UNSERIALIZE_PASSTHRU, ht, elements, 1)) { + if (has_wakeup) { + ZVAL_DEREF(rval); + GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED; + } return 0; } - if (Z_TYPE_PP(rval) != IS_OBJECT) { - return 0; - } - - if (Z_OBJCE_PP(rval) != PHP_IC_ENTRY && - zend_hash_exists(&Z_OBJCE_PP(rval)->function_table, "__wakeup", sizeof("__wakeup"))) { - INIT_PZVAL(&fname); - ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0); + ZVAL_DEREF(rval); + if (has_wakeup) { + ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1); BG(serialize_lock)++; - call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC); + if (call_user_function_ex(CG(function_table), rval, &fname, &retval, 0, 0, 1, NULL) == FAILURE || Z_ISUNDEF(retval)) { + GC_FLAGS(Z_OBJ_P(rval)) |= IS_OBJ_DESTRUCTOR_CALLED; + } BG(serialize_lock)--; - } - - if (retval_ptr) { - zval_ptr_dtor(&retval_ptr); + zval_dtor(&fname); + zval_dtor(&retval); } if (EG(exception)) { @@ -470,16 +498,48 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) } return finish_nested_data(UNSERIALIZE_PASSTHRU); - } #ifdef PHP_WIN32 # pragma optimize("", on) #endif -PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) +PHPAPI int php_var_unserialize(zval *rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash) +{ + HashTable *classes = NULL; + return php_var_unserialize_ex(UNSERIALIZE_PASSTHRU); +} + +PHPAPI int php_var_unserialize_ex(UNSERIALIZE_PARAMETER) +{ + var_entries *orig_var_entries = (*var_hash)->last; + zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0; + int result; + + result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU); + + if (!result) { + /* If the unserialization failed, mark all elements that have been added to var_hash + * as NULL. This will forbid their use by other unserialize() calls in the same + * unserialization context. */ + var_entries *e = orig_var_entries; + zend_long s = orig_used_slots; + while (e) { + for (; s < e->used_slots; s++) { + e->data[s] = NULL; + } + + e = e->next; + s = 0; + } + } + + return result; +} + +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; - zval **rval_ref; + zval *rval_ref; limit = max; cursor = *p; @@ -488,16 +548,14 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 0; } - if (var_hash && cursor[0] != 'R') { + if (var_hash && (*p)[0] != 'R') { var_push(var_hash, rval); } start = cursor; - - -#line 501 "ext/standard/var_unserializer.c" +#line 559 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -557,9 +615,9 @@ yy2: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 877 "ext/standard/var_unserializer.re" +#line 936 "ext/standard/var_unserializer.re" { return 0; } -#line 563 "ext/standard/var_unserializer.c" +#line 621 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -602,13 +660,13 @@ yy13: goto yy3; yy14: ++YYCURSOR; -#line 871 "ext/standard/var_unserializer.re" +#line 930 "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"); + php_error_docref(NULL, E_NOTICE, "Unexpected end of serialized data"); return 0; /* not sure if it should be 0 or 1 here? */ } -#line 612 "ext/standard/var_unserializer.c" +#line 670 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -639,28 +697,26 @@ yy20: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 717 "ext/standard/var_unserializer.re" +#line 778 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; - long elements; - char *class_name; + zend_long elements; + char *str; + zend_string *class_name; zend_class_entry *ce; - zend_class_entry **pce; int incomplete_class = 0; int custom_object = 0; - zval *user_func; - zval *retval_ptr; - zval **args[1]; - zval *arg_func_name; + zval user_func; + zval retval; + zval args[1]; if (!var_hash) return 0; if (*start == 'C') { custom_object = 1; } - INIT_PZVAL(*rval); len2 = len = parse_uiv(start + 2); maxlen = max - YYCURSOR; if (maxlen < len || len == 0) { @@ -668,7 +724,7 @@ yy20: return 0; } - class_name = (char*)YYCURSOR; + str = (char*)YYCURSOR; YYCURSOR += len; @@ -681,31 +737,37 @@ yy20: return 0; } - len3 = strspn(class_name, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\"); + len3 = strspn(str, "0123456789_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\177\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377\\"); if (len3 != len) { *p = YYCURSOR + len3 - len; return 0; } - class_name = estrndup(class_name, len); + class_name = zend_string_init(str, len, 0); do { + if(!unserialize_allowed_class(class_name, classes)) { + incomplete_class = 1; + ce = PHP_IC_ENTRY; + break; + } + /* Try to find class directly */ BG(serialize_lock)++; - if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) { + ce = zend_lookup_class(class_name); + if (ce) { BG(serialize_lock)--; if (EG(exception)) { - efree(class_name); + zend_string_release(class_name); return 0; } - ce = *pce; break; } BG(serialize_lock)--; if (EG(exception)) { - efree(class_name); + zend_string_release(class_name); return 0; } @@ -717,51 +779,45 @@ yy20: } /* Call unserialize callback */ - MAKE_STD_ZVAL(user_func); - ZVAL_STRING(user_func, PG(unserialize_callback_func), 1); - args[0] = &arg_func_name; - MAKE_STD_ZVAL(arg_func_name); - ZVAL_STRING(arg_func_name, class_name, 1); + ZVAL_STRING(&user_func, PG(unserialize_callback_func)); + + ZVAL_STR_COPY(&args[0], class_name); BG(serialize_lock)++; - if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) { + if (call_user_function_ex(CG(function_table), NULL, &user_func, &retval, 1, args, 0, NULL) != SUCCESS) { BG(serialize_lock)--; if (EG(exception)) { - efree(class_name); + zend_string_release(class_name); zval_ptr_dtor(&user_func); - zval_ptr_dtor(&arg_func_name); + zval_ptr_dtor(&args[0]); return 0; } - php_error_docref(NULL TSRMLS_CC, E_WARNING, "defined (%s) but not found", user_func->value.str.val); + php_error_docref(NULL, E_WARNING, "defined (%s) but not found", Z_STRVAL(user_func)); incomplete_class = 1; ce = PHP_IC_ENTRY; zval_ptr_dtor(&user_func); - zval_ptr_dtor(&arg_func_name); + zval_ptr_dtor(&args[0]); break; } BG(serialize_lock)--; - if (retval_ptr) { - zval_ptr_dtor(&retval_ptr); - } + zval_ptr_dtor(&retval); if (EG(exception)) { - efree(class_name); + zend_string_release(class_name); zval_ptr_dtor(&user_func); - zval_ptr_dtor(&arg_func_name); + zval_ptr_dtor(&args[0]); return 0; } /* The callback function may have defined the class */ BG(serialize_lock)++; - if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) { - ce = *pce; - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function %s() hasn't defined the class it was called for", user_func->value.str.val); + if ((ce = zend_lookup_class(class_name)) == NULL) { + php_error_docref(NULL, E_WARNING, "Function %s() hasn't defined the class it was called for", Z_STRVAL(user_func)); incomplete_class = 1; ce = PHP_IC_ENTRY; } BG(serialize_lock)--; zval_ptr_dtor(&user_func); - zval_ptr_dtor(&arg_func_name); + zval_ptr_dtor(&args[0]); break; } while (1); @@ -773,9 +829,9 @@ yy20: ret = object_custom(UNSERIALIZE_PASSTHRU, ce); if (ret && incomplete_class) { - php_store_class_name(*rval, class_name, len2); + php_store_class_name(rval, ZSTR_VAL(class_name), len2); } - efree(class_name); + zend_string_release(class_name); return ret; } @@ -787,13 +843,13 @@ yy20: } if (incomplete_class) { - php_store_class_name(*rval, class_name, len2); + php_store_class_name(rval, ZSTR_VAL(class_name), len2); } - efree(class_name); + zend_string_release(class_name); return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 797 "ext/standard/var_unserializer.c" +#line 853 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -818,20 +874,18 @@ yy27: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 704 "ext/standard/var_unserializer.re" +#line 767 "ext/standard/var_unserializer.re" { long elements; if (!var_hash) return 0; - INIT_PZVAL(*rval); - elements = object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR); if (elements < 0) { return 0; } return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 835 "ext/standard/var_unserializer.c" +#line 889 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -852,9 +906,9 @@ yy34: yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 683 "ext/standard/var_unserializer.re" +#line 743 "ext/standard/var_unserializer.re" { - long elements = parse_iv(start + 2); + zend_long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ *p = YYCURSOR; if (!var_hash) return 0; @@ -863,17 +917,20 @@ yy34: return 0; } - INIT_PZVAL(*rval); - - array_init_size(*rval, elements); + array_init_size(rval, elements); + 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); + } - if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) { + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_P(rval), elements, 0)) { return 0; } return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 877 "ext/standard/var_unserializer.c" +#line 934 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -894,10 +951,10 @@ yy41: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 648 "ext/standard/var_unserializer.re" +#line 709 "ext/standard/var_unserializer.re" { size_t len, maxlen; - char *str; + zend_string *str; len = parse_uiv(start + 2); maxlen = max - YYCURSOR; @@ -906,12 +963,12 @@ yy41: return 0; } - if ((str = unserialize_str(&YYCURSOR, &len, maxlen)) == NULL) { + if ((str = unserialize_str(&YYCURSOR, len, maxlen)) == NULL) { return 0; } if (*(YYCURSOR) != '"') { - efree(str); + zend_string_free(str); *p = YYCURSOR; return 0; } @@ -925,11 +982,10 @@ yy41: YYCURSOR += 2; *p = YYCURSOR; - INIT_PZVAL(*rval); - ZVAL_STRINGL(*rval, str, len, 0); + ZVAL_STR(rval, str); return 1; } -#line 933 "ext/standard/var_unserializer.c" +#line 989 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -950,7 +1006,7 @@ yy48: yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 615 "ext/standard/var_unserializer.re" +#line 677 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -979,11 +1035,10 @@ yy48: YYCURSOR += 2; *p = YYCURSOR; - INIT_PZVAL(*rval); - ZVAL_STRINGL(*rval, str, len, 1); + ZVAL_STRINGL(rval, str, len); return 1; } -#line 987 "ext/standard/var_unserializer.c" +#line 1042 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1071,17 +1126,16 @@ yy61: } yy63: ++YYCURSOR; -#line 605 "ext/standard/var_unserializer.re" +#line 668 "ext/standard/var_unserializer.re" { -#if SIZEOF_LONG == 4 +#if SIZEOF_ZEND_LONG == 4 use_double: #endif *p = YYCURSOR; - INIT_PZVAL(*rval); - ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); + ZVAL_DOUBLE(rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1085 "ext/standard/var_unserializer.c" +#line 1139 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1140,22 +1194,23 @@ yy73: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 590 "ext/standard/var_unserializer.re" +#line 652 "ext/standard/var_unserializer.re" { *p = YYCURSOR; - INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { - ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { - ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { - ZVAL_DOUBLE(*rval, -php_get_inf()); + if (!strncmp((char*)start + 2, "NAN", 3)) { + ZVAL_DOUBLE(rval, php_get_nan()); + } else if (!strncmp((char*)start + 2, "INF", 3)) { + ZVAL_DOUBLE(rval, php_get_inf()); + } else if (!strncmp((char*)start + 2, "-INF", 4)) { + ZVAL_DOUBLE(rval, -php_get_inf()); + } else { + ZVAL_NULL(rval); } return 1; } -#line 1159 "ext/standard/var_unserializer.c" +#line 1214 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1182,19 +1237,19 @@ yy79: if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 563 "ext/standard/var_unserializer.re" +#line 626 "ext/standard/var_unserializer.re" { -#if SIZEOF_LONG == 4 +#if SIZEOF_ZEND_LONG == 4 int digits = YYCURSOR - start - 3; if (start[2] == '-' || start[2] == '+') { digits--; } - /* Use double for large long values that were serialized on a 64-bit system */ + /* Use double for large zend_long values that were serialized on a 64-bit system */ if (digits >= MAX_LENGTH_OF_LONG - 1) { if (digits == MAX_LENGTH_OF_LONG - 1) { - int cmp = strncmp(YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1); + int cmp = strncmp((char*)YYCURSOR - MAX_LENGTH_OF_LONG, long_min_digits, MAX_LENGTH_OF_LONG - 1); if (!(cmp < 0 || (cmp == 0 && start[2] == '-'))) { goto use_double; @@ -1205,11 +1260,10 @@ yy79: } #endif *p = YYCURSOR; - INIT_PZVAL(*rval); - ZVAL_LONG(*rval, parse_iv(start + 2)); + ZVAL_LONG(rval, parse_iv(start + 2)); return 1; } -#line 1213 "ext/standard/var_unserializer.c" +#line 1267 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1217,24 +1271,22 @@ yy83: yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 556 "ext/standard/var_unserializer.re" +#line 620 "ext/standard/var_unserializer.re" { *p = YYCURSOR; - INIT_PZVAL(*rval); - ZVAL_BOOL(*rval, parse_iv(start + 2)); + ZVAL_BOOL(rval, parse_iv(start + 2)); return 1; } -#line 1228 "ext/standard/var_unserializer.c" +#line 1281 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 549 "ext/standard/var_unserializer.re" +#line 614 "ext/standard/var_unserializer.re" { *p = YYCURSOR; - INIT_PZVAL(*rval); - ZVAL_NULL(*rval); + ZVAL_NULL(rval); return 1; } -#line 1238 "ext/standard/var_unserializer.c" +#line 1290 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1257,30 +1309,32 @@ yy91: if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 526 "ext/standard/var_unserializer.re" +#line 589 "ext/standard/var_unserializer.re" { - long id; + zend_long id; *p = YYCURSOR; if (!var_hash) return 0; id = parse_iv(start + 2) - 1; - if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) { + if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) { return 0; } - if (*rval == *rval_ref) return 0; + if (rval_ref == rval) { + return 0; + } - if (*rval != NULL) { - var_push_dtor_no_addref(var_hash, rval); + if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) { + ZVAL_UNDEF(rval); + return 1; } - *rval = *rval_ref; - Z_ADDREF_PP(rval); - Z_UNSET_ISREF_PP(rval); + + ZVAL_COPY(rval, rval_ref); return 1; } -#line 1284 "ext/standard/var_unserializer.c" +#line 1338 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1303,30 +1357,35 @@ yy97: if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 505 "ext/standard/var_unserializer.re" +#line 563 "ext/standard/var_unserializer.re" { - long id; + zend_long id; *p = YYCURSOR; if (!var_hash) return 0; id = parse_iv(start + 2) - 1; - if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) { + if (id == -1 || (rval_ref = var_access(var_hash, id)) == NULL) { return 0; } - if (*rval != NULL) { - var_push_dtor_no_addref(var_hash, rval); + zval_ptr_dtor(rval); + if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) { + ZVAL_UNDEF(rval); + return 1; + } + if (Z_ISREF_P(rval_ref)) { + ZVAL_COPY(rval, rval_ref); + } else { + ZVAL_NEW_REF(rval_ref, rval_ref); + ZVAL_COPY(rval, rval_ref); } - *rval = *rval_ref; - Z_ADDREF_PP(rval); - Z_SET_ISREF_PP(rval); return 1; } -#line 1328 "ext/standard/var_unserializer.c" +#line 1387 "ext/standard/var_unserializer.c" } -#line 879 "ext/standard/var_unserializer.re" +#line 938 "ext/standard/var_unserializer.re" return 0; |
