summaryrefslogtreecommitdiff
path: root/ext/standard/var_unserializer.re
diff options
context:
space:
mode:
Diffstat (limited to 'ext/standard/var_unserializer.re')
-rw-r--r--ext/standard/var_unserializer.re106
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