diff options
Diffstat (limited to 'ext/standard/var_unserializer.re')
-rw-r--r-- | ext/standard/var_unserializer.re | 106 |
1 files changed, 71 insertions, 35 deletions
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 8db79bed5f..67348af0ba 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -328,22 +328,43 @@ object = [OC]; static inline zend_long parse_iv2(const unsigned char *p, const unsigned char **q) { - zend_long result = 0; - char *end; + zend_ulong result = 0; + zend_ulong neg = 0; + const unsigned char *start; - errno = 0; - result = ZEND_STRTOL((const char*)p, &end, 0); + if (*p == '-') { + neg = 1; + p++; + } else if (UNEXPECTED(*p == '+')) { + p++; + } + + while (UNEXPECTED(*p == '0')) { + p++; + } + + start = p; + + while (*p >= '0' && *p <= '9') { + result = result * 10 + ((zend_ulong)(*p) - '0'); + p++; + } if (q) { - *q = (const unsigned char *)end; + *q = p; } - if (errno) { - php_error_docref(NULL, E_WARNING, "%s", strerror(errno)); - return result; + /* number too long or overflow */ + if (UNEXPECTED(p - start > MAX_LENGTH_OF_LONG - 1) + || (SIZEOF_ZEND_LONG == 4 + && UNEXPECTED(p - start == MAX_LENGTH_OF_LONG - 1) + && UNEXPECTED(*start > '2')) + || UNEXPECTED(result - neg > ZEND_LONG_MAX)) { + php_error_docref(NULL, E_WARNING, "Numerical result out of range"); + return (!neg) ? ZEND_LONG_MAX : ZEND_LONG_MIN; } - return result; + return (!neg) ? (zend_long)result : -(zend_long)result; } static inline zend_long parse_iv(const unsigned char *p) @@ -372,7 +393,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 #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash -static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER); +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key); static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, zend_long elements, int objprops) { @@ -382,7 +403,7 @@ static zend_always_inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTab ZVAL_UNDEF(&key); - if (!php_var_unserialize_internal(&key, p, max, NULL)) { + if (!php_var_unserialize_internal(&key, p, max, NULL, 1)) { zval_ptr_dtor(&key); return 0; } @@ -419,12 +440,14 @@ numeric_key: } else { if (EXPECTED(Z_TYPE(key) == IS_STRING)) { string_key: - { + if (Z_TYPE_P(rval) == IS_OBJECT + && zend_hash_num_elements(&Z_OBJCE_P(rval)->properties_info) > 0) { zend_property_info *existing_propinfo; - zend_string *new_key, *unmangled; + zend_string *new_key; const char *unmangled_class = NULL; const char *unmangled_prop; size_t unmangled_prop_len; + zend_string *unmangled; if (UNEXPECTED(zend_unmangle_property_name_ex(Z_STR(key), &unmangled_class, &unmangled_prop, &unmangled_prop_len) == FAILURE)) { zval_ptr_dtor(&key); @@ -432,24 +455,25 @@ string_key: } unmangled = zend_string_init(unmangled_prop, unmangled_prop_len, 0); - if (Z_TYPE_P(rval) == IS_OBJECT - && ((existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled)) != NULL) + + existing_propinfo = zend_hash_find_ptr(&Z_OBJCE_P(rval)->properties_info, unmangled); + if ((existing_propinfo != NULL) && (existing_propinfo->flags & ZEND_ACC_PPP_MASK)) { if (existing_propinfo->flags & ZEND_ACC_PROTECTED) { new_key = zend_mangle_property_name( - "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); + "*", 1, ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), 0); zend_string_release(unmangled); } else if (existing_propinfo->flags & ZEND_ACC_PRIVATE) { if (unmangled_class != NULL && strcmp(unmangled_class, "*") != 0) { new_key = zend_mangle_property_name( unmangled_class, strlen(unmangled_class), - ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), - Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); + ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), + 0); } else { new_key = zend_mangle_property_name( ZSTR_VAL(existing_propinfo->ce->name), ZSTR_LEN(existing_propinfo->ce->name), ZSTR_VAL(unmangled), ZSTR_LEN(unmangled), - Z_OBJCE_P(rval)->type & ZEND_INTERNAL_CLASS); + 0); } zend_string_release(unmangled); } else { @@ -461,16 +485,16 @@ string_key: } else { zend_string_release(unmangled); } + } - 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); + 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 */ @@ -482,7 +506,7 @@ string_key: } } - if (!php_var_unserialize_internal(data, p, max, var_hash)) { + if (!php_var_unserialize_internal(data, p, max, var_hash, 0)) { zval_ptr_dtor(&key); return 0; } @@ -575,7 +599,7 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, zend_long elements) && zend_hash_str_exists(&Z_OBJCE_P(rval)->function_table, "__wakeup", sizeof("__wakeup")-1); ht = Z_OBJPROP_P(rval); - if (elements >= HT_MAX_SIZE - zend_hash_num_elements(ht)) { + if (elements >= (zend_long)(HT_MAX_SIZE - zend_hash_num_elements(ht))) { return 0; } @@ -608,7 +632,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) zend_long orig_used_slots = orig_var_entries ? orig_var_entries->used_slots : 0; int result; - result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU); + result = php_var_unserialize_internal(UNSERIALIZE_PASSTHRU, 0); if (!result) { /* If the unserialization failed, mark all elements that have been added to var_hash @@ -629,7 +653,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return result; } -static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) +static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER, int as_key) { const unsigned char *cursor, *limit, *marker, *start; zval *rval_ref; @@ -689,7 +713,8 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) return 0; } - if (Z_ISUNDEF_P(rval_ref) || (Z_ISREF_P(rval_ref) && Z_ISUNDEF_P(Z_REFVAL_P(rval_ref)))) { + ZVAL_DEREF(rval_ref); + if (Z_TYPE_P(rval_ref) != IS_OBJECT) { return 0; } @@ -704,9 +729,15 @@ static int php_var_unserialize_internal(UNSERIALIZE_PARAMETER) return 1; } -"b:" [01] ";" { +"b:0;" { + *p = YYCURSOR; + ZVAL_FALSE(rval); + return 1; +} + +"b:1;" { *p = YYCURSOR; - ZVAL_BOOL(rval, parse_iv(start + 2)); + ZVAL_TRUE(rval); return 1; } @@ -793,6 +824,8 @@ use_double: ZVAL_EMPTY_STRING(rval); } else if (len == 1) { ZVAL_INTERNED_STR(rval, ZSTR_CHAR((zend_uchar)*str)); + } else if (as_key) { + ZVAL_STR(rval, zend_string_init_interned(str, len, 0)); } else { ZVAL_STRINGL(rval, str, len); } @@ -843,11 +876,14 @@ use_double: return 0; } - array_init_size(rval, elements); if (elements) { + 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) */ zend_hash_real_init(Z_ARRVAL_P(rval), 0); + } else { + ZVAL_EMPTY_ARRAY(rval); + return finish_nested_data(UNSERIALIZE_PASSTHRU); } /* The array may contain references to itself, in which case we'll be modifying an |