From e6a3ff0dac5ad1c9f4565e5636a811d16337e4c9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 11 Aug 2013 19:21:59 +0100 Subject: [PATCH 1/9] Add new PHPAPI functions for serializing object and its properties --- ext/standard/php_var.h | 42 +++++++- ext/standard/var.c | 219 +++++++++++++++++++++++++++++------------ 2 files changed, 199 insertions(+), 62 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 35343b3d5d068..261aec730c3ab 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -38,8 +38,47 @@ PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC); + +#define PHP_SERIALIZE_FAILURE (FAILURE) +#define PHP_SERIALIZE_CUSTOM (SUCCESS) +#define PHP_SERIALIZE_OBJECT (SUCCESS + 1) + typedef HashTable* php_serialize_data_t; +/* serialize variable */ +PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); + +/* add object serialization string prefix */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC); + +/* append string that ends the object definition */ +PHPAPI void php_var_serialize_object_end(smart_str *buf); + +/* append null property */ +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key); + +/* append boolean property */ +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value); + +/* append long property */ +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value); + +/* append double property */ +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC); + +/* append string property */ +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value); + +/* append string property */ +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len); + +/* append string property zval */ +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC); + +/* append properties taken from HashTable */ +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC); + + struct php_unserialize_data { void *first; void *last; @@ -49,9 +88,10 @@ struct php_unserialize_data { typedef struct php_unserialize_data* php_unserialize_data_t; -PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); + + #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ do { \ /* fprintf(stderr, "SERIALIZE_INIT == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */ \ diff --git a/ext/standard/var.c b/ext/standard/var.c index c1e7c2f3ee346..81bb1a71d3025 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -584,6 +584,20 @@ static inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old } /* }}} */ +static inline void php_var_serialize_null(smart_str *buf) /* {{{ */ +{ + smart_str_appendl(buf, "N;", 2); +} +/* }}} */ + +static inline void php_var_serialize_bool(smart_str *buf, long val) /* {{{ */ +{ + smart_str_appendl(buf, "b:", 2); + smart_str_append_long(buf, val); + smart_str_appendc(buf, ';'); +} +/* }}} */ + static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ { smart_str_appendl(buf, "i:", 2); @@ -592,7 +606,21 @@ static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ } /* }}} */ -static inline void php_var_serialize_string(smart_str *buf, char *str, int len) /* {{{ */ +static inline void php_var_serialize_double(smart_str *buf, double val TSRMLS_DC) /* {{{ */ +{ + char *s; + + smart_str_appendl(buf, "d:", 2); + s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); + php_gcvt(val, PG(serialize_precision), '.', 'E', s); + smart_str_appends(buf, s); + smart_str_appendc(buf, ';'); + efree(s); + return; +} +/* }}} */ + +static inline void php_var_serialize_string(smart_str *buf, const char *str, int len) /* {{{ */ { smart_str_appendl(buf, "s:", 2); smart_str_append_long(buf, len); @@ -602,6 +630,55 @@ static inline void php_var_serialize_string(smart_str *buf, char *str, int len) } /* }}} */ +static inline void php_var_serialize_hash_table(smart_str *buf, HashTable *myht, zval **pstruc, zend_bool incomplete_class, HashTable *var_hash TSRMLS_DC) /* {{{ */ +{ + int i; + char *key; + zval **data; + ulong index; + uint key_len; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(myht, &pos); + for (;; zend_hash_move_forward_ex(myht, &pos)) { + i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); + if (i == HASH_KEY_NON_EXISTENT) { + break; + } + if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { + continue; + } + + switch (i) { + case HASH_KEY_IS_LONG: + php_var_serialize_long(buf, index); + break; + case HASH_KEY_IS_STRING: + php_var_serialize_string(buf, key, key_len - 1); + break; + } + + /* we should still add element even if it's not OK, + * since we already wrote the length of the array before */ + if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS + || !data + || data == pstruc + || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) + ) { + smart_str_appendl(buf, "N;", 2); + } else { + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount++; + } + php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount--; + } + } + } +} +/* }}} */ + static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc TSRMLS_DC) /* {{{ */ { PHP_CLASS_ATTRIBUTES; @@ -734,30 +811,20 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var switch (Z_TYPE_P(struc)) { case IS_BOOL: - smart_str_appendl(buf, "b:", 2); - smart_str_append_long(buf, Z_LVAL_P(struc)); - smart_str_appendc(buf, ';'); + php_var_serialize_bool(buf, Z_LVAL_P(struc)); return; case IS_NULL: - smart_str_appendl(buf, "N;", 2); + php_var_serialize_null(buf); return; case IS_LONG: php_var_serialize_long(buf, Z_LVAL_P(struc)); return; - case IS_DOUBLE: { - char *s; - - smart_str_appendl(buf, "d:", 2); - s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); - php_gcvt(Z_DVAL_P(struc), PG(serialize_precision), '.', 'E', s); - smart_str_appends(buf, s); - smart_str_appendc(buf, ';'); - efree(s); - return; - } + case IS_DOUBLE: + php_var_serialize_double(buf, Z_DVAL_P(struc) TSRMLS_CC); + return; case IS_STRING: php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc)); @@ -766,7 +833,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var case IS_OBJECT: { zval *retval_ptr = NULL; zval fname; - int res; + int res, serialize_rc; zend_class_entry *ce = NULL; if (Z_OBJ_HT_P(struc)->get_class_entry) { @@ -778,7 +845,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var unsigned char *serialized_data = NULL; zend_uint serialized_length; - if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC) == SUCCESS) { + serialize_rc = ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC); + if (serialize_rc == PHP_SERIALIZE_CUSTOM) { smart_str_appendl(buf, "C:", 2); smart_str_append_long(buf, (int)Z_OBJCE_P(struc)->name_length); smart_str_appendl(buf, ":\"", 2); @@ -789,6 +857,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_appendl(buf, ":{", 2); smart_str_appendl(buf, serialized_data, serialized_length); smart_str_appendc(buf, '}'); + } else if (serialize_rc == PHP_SERIALIZE_OBJECT) { + smart_str_appendl(buf, serialized_data, serialized_length); } else { smart_str_appendl(buf, "N;", 2); } @@ -851,49 +921,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_append_long(buf, i); smart_str_appendl(buf, ":{", 2); if (i > 0) { - char *key; - zval **data; - ulong index; - uint key_len; - HashPosition pos; - - zend_hash_internal_pointer_reset_ex(myht, &pos); - for (;; zend_hash_move_forward_ex(myht, &pos)) { - i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); - if (i == HASH_KEY_NON_EXISTENT) { - break; - } - if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { - continue; - } - - switch (i) { - case HASH_KEY_IS_LONG: - php_var_serialize_long(buf, index); - break; - case HASH_KEY_IS_STRING: - php_var_serialize_string(buf, key, key_len - 1); - break; - } - - /* we should still add element even if it's not OK, - * since we already wrote the length of the array before */ - if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS - || !data - || data == &struc - || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) - ) { - smart_str_appendl(buf, "N;", 2); - } else { - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount++; - } - php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount--; - } - } - } + php_var_serialize_hash_table(buf, myht, &struc, incomplete_class, var_hash TSRMLS_CC); } smart_str_appendc(buf, '}'); return; @@ -912,6 +940,75 @@ PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t } /* }}} */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_class_name(buf, object TSRMLS_CC); + smart_str_append_long(buf, nprops); + smart_str_appendl(buf, ":{", 2); +} +/* }}} */ + +PHPAPI void php_var_serialize_object_end(smart_str *buf) /* {{{ */ +{ + smart_str_appendc(buf, '}'); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_bool(buf, value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_long(buf, value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_double(buf, value TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, strlen(value)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, value_len); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_intern(buf, value, var_hash TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_hash_table(buf, properties, NULL, 0, var_hash TSRMLS_CC); +} +/* }}} */ + + /* {{{ proto string serialize(mixed variable) Returns a string representation of variable (which can later be unserialized) */ PHP_FUNCTION(serialize) From 172d862da06c408be66d04a1e7b5d5f2765c8924 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 1 Sep 2013 17:08:14 +0100 Subject: [PATCH 2/9] Call unserialize for non-custom object --- ext/standard/var_unserializer.c | 44 ++++++++++++++++++++------------ ext/standard/var_unserializer.re | 12 ++++++++- 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index ddf43b02cf14d..e7a46a1343def 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 */ +/* Generated by re2c 0.13.6 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -354,7 +354,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) 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) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -492,7 +492,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 785 "ext/standard/var_unserializer.re" +#line 795 "ext/standard/var_unserializer.re" { return 0; } #line 498 "ext/standard/var_unserializer.c" yy4: @@ -537,7 +537,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 779 "ext/standard/var_unserializer.re" +#line 789 "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"); @@ -715,9 +715,19 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } efree(class_name); + /* custom unserialization for non-custom objects */ + if (ce->unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + (*p) += ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 721 "ext/standard/var_unserializer.c" +#line 731 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -750,7 +760,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 754 "ext/standard/var_unserializer.c" +#line 764 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -791,7 +801,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 795 "ext/standard/var_unserializer.c" +#line 805 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -841,7 +851,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 845 "ext/standard/var_unserializer.c" +#line 855 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -890,7 +900,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 894 "ext/standard/var_unserializer.c" +#line 904 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -988,7 +998,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 992 "ext/standard/var_unserializer.c" +#line 1002 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1062,7 +1072,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1066 "ext/standard/var_unserializer.c" +#line 1076 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1116,7 +1126,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1120 "ext/standard/var_unserializer.c" +#line 1130 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1131,7 +1141,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1135 "ext/standard/var_unserializer.c" +#line 1145 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; #line 484 "ext/standard/var_unserializer.re" @@ -1141,7 +1151,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_NULL(*rval); return 1; } -#line 1145 "ext/standard/var_unserializer.c" +#line 1155 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1187,7 +1197,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1191 "ext/standard/var_unserializer.c" +#line 1201 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1231,9 +1241,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1235 "ext/standard/var_unserializer.c" +#line 1245 "ext/standard/var_unserializer.c" } -#line 787 "ext/standard/var_unserializer.re" +#line 797 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 4d99cbfd78944..22f853d7f17df 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -358,7 +358,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) 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) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -773,6 +773,16 @@ object ":" uiv ":" ["] { } efree(class_name); + /* custom unserialization for non-custom objects */ + if (ce->unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + (*p) += ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } From 1402ce2c54e4eb091ce34905499fc3a98f89018c Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 7 Sep 2013 18:26:50 +0100 Subject: [PATCH 3/9] Add new PHPAPI functions for unserializing object properties --- ext/standard/php_var.h | 6 ++ ext/standard/var_unserializer.c | 134 +++++++++++++++++++++++-------- ext/standard/var_unserializer.re | 74 ++++++++++++++++- 3 files changed, 178 insertions(+), 36 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 261aec730c3ab..21ba8c90624c2 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -88,8 +88,14 @@ struct php_unserialize_data { typedef struct php_unserialize_data* php_unserialize_data_t; +/* unserialize variable */ PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); +/* unserialize one property (key and value) of the serialized object */ +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); + +/* unserialize all properties of the serialized object and save them to ht */ +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC); #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index e7a46a1343def..22085d62d56c2 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -411,6 +411,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -432,7 +499,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 436 "ext/standard/var_unserializer.c" +#line 503 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -492,9 +559,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 795 "ext/standard/var_unserializer.re" +#line 863 "ext/standard/var_unserializer.re" { return 0; } -#line 498 "ext/standard/var_unserializer.c" +#line 565 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -537,13 +604,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 789 "ext/standard/var_unserializer.re" +#line 857 "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 547 "ext/standard/var_unserializer.c" +#line 614 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -573,7 +640,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 635 "ext/standard/var_unserializer.re" +#line 702 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -715,19 +782,20 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } efree(class_name); - /* custom unserialization for non-custom objects */ + /* custom unserialization for objects that are not custom (C: prefix) */ if (ce->unserialize) { - int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; } - (*p) += ret; + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; return finish_nested_data(UNSERIALIZE_PASSTHRU); } return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 731 "ext/standard/var_unserializer.c" +#line 799 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -752,7 +820,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 627 "ext/standard/var_unserializer.re" +#line 694 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -760,7 +828,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 764 "ext/standard/var_unserializer.c" +#line 832 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -781,7 +849,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 607 "ext/standard/var_unserializer.re" +#line 674 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -801,7 +869,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 805 "ext/standard/var_unserializer.c" +#line 873 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -822,7 +890,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 578 "ext/standard/var_unserializer.re" +#line 645 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -851,7 +919,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 855 "ext/standard/var_unserializer.c" +#line 923 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -872,7 +940,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 550 "ext/standard/var_unserializer.re" +#line 617 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -900,7 +968,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 904 "ext/standard/var_unserializer.c" +#line 972 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -988,7 +1056,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 540 "ext/standard/var_unserializer.re" +#line 607 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -998,7 +1066,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1002 "ext/standard/var_unserializer.c" +#line 1070 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1057,7 +1125,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 525 "ext/standard/var_unserializer.re" +#line 592 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -1072,7 +1140,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1076 "ext/standard/var_unserializer.c" +#line 1144 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1099,7 +1167,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 498 "ext/standard/var_unserializer.re" +#line 565 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1126,7 +1194,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1130 "ext/standard/var_unserializer.c" +#line 1198 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1134,24 +1202,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 491 "ext/standard/var_unserializer.re" +#line 558 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1145 "ext/standard/var_unserializer.c" +#line 1213 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 484 "ext/standard/var_unserializer.re" +#line 551 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1155 "ext/standard/var_unserializer.c" +#line 1223 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1174,7 +1242,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 461 "ext/standard/var_unserializer.re" +#line 528 "ext/standard/var_unserializer.re" { long id; @@ -1197,7 +1265,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1201 "ext/standard/var_unserializer.c" +#line 1269 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1220,7 +1288,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 440 "ext/standard/var_unserializer.re" +#line 507 "ext/standard/var_unserializer.re" { long id; @@ -1241,9 +1309,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1245 "ext/standard/var_unserializer.c" +#line 1313 "ext/standard/var_unserializer.c" } -#line 797 "ext/standard/var_unserializer.re" +#line 865 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 22f853d7f17df..190eb5c3258f1 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -415,6 +415,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -773,13 +840,14 @@ object ":" uiv ":" ["] { } efree(class_name); - /* custom unserialization for non-custom objects */ + /* custom unserialization for objects that are not custom (C: prefix) */ if (ce->unserialize) { - int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, elements, (zend_unserialize_data *)var_hash TSRMLS_CC); + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; } - (*p) += ret; + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; return finish_nested_data(UNSERIALIZE_PASSTHRU); } From ef668e8914be008c148091a63ff6ca9bb0da0ffc Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 8 Sep 2013 20:30:49 +0100 Subject: [PATCH 4/9] Use int when serialize bool --- ext/standard/php_var.h | 2 +- ext/standard/var.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 21ba8c90624c2..bed3aa391bb0f 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -58,7 +58,7 @@ PHPAPI void php_var_serialize_object_end(smart_str *buf); PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key); /* append boolean property */ -PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value); +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value); /* append long property */ PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value); diff --git a/ext/standard/var.c b/ext/standard/var.c index 81bb1a71d3025..2fe4d1e000c04 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -960,10 +960,10 @@ PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key) /* } /* }}} */ -PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, long value) /* {{{ */ +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value) /* {{{ */ { php_var_serialize_string(buf, key, strlen(key)); - php_var_serialize_bool(buf, value); + php_var_serialize_bool(buf, (long) value); } /* }}} */ From 0d81fbaef8bcd69e2be92ea92c43853cabe91a18 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 11 Sep 2013 20:21:31 +0100 Subject: [PATCH 5/9] Change vah_hash type for zval and ht serialization --- ext/standard/php_var.h | 4 ++-- ext/standard/var.c | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index bed3aa391bb0f..4f31e1a3e90d3 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -73,10 +73,10 @@ PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, c PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len); /* append string property zval */ -PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC); +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC); /* append properties taken from HashTable */ -PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC); +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC); struct php_unserialize_data { diff --git a/ext/standard/var.c b/ext/standard/var.c index 2fe4d1e000c04..4194873d57ccf 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -995,16 +995,16 @@ PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, } /* }}} */ -PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC) /* {{{ */ { php_var_serialize_string(buf, key, strlen(key)); - php_var_serialize_intern(buf, value, var_hash TSRMLS_CC); + php_var_serialize_intern(buf, value, (HashTable *) data TSRMLS_CC); } /* }}} */ -PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, php_serialize_data_t var_hash TSRMLS_DC) /* {{{ */ +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC) /* {{{ */ { - php_var_serialize_hash_table(buf, properties, NULL, 0, var_hash TSRMLS_CC); + php_var_serialize_hash_table(buf, properties, NULL, 0, (HashTable *) data TSRMLS_CC); } /* }}} */ From 1b793d6b09dac3ddc5f7aaf9e9dc9d22de9c485c Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 14 Sep 2013 18:39:56 +0100 Subject: [PATCH 6/9] Use unserialize callback only for internal classes --- ext/standard/var_unserializer.c | 71 ++++++++++++++++---------------- ext/standard/var_unserializer.re | 9 ++-- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 22085d62d56c2..579d5f29c02ea 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -23,6 +23,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -201,7 +202,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen #define YYMARKER marker -#line 209 "ext/standard/var_unserializer.re" +#line 210 "ext/standard/var_unserializer.re" @@ -499,7 +500,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 503 "ext/standard/var_unserializer.c" +#line 504 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -559,9 +560,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 863 "ext/standard/var_unserializer.re" +#line 864 "ext/standard/var_unserializer.re" { return 0; } -#line 565 "ext/standard/var_unserializer.c" +#line 566 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -604,13 +605,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 857 "ext/standard/var_unserializer.re" +#line 858 "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 614 "ext/standard/var_unserializer.c" +#line 615 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -640,7 +641,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 702 "ext/standard/var_unserializer.re" +#line 703 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -783,7 +784,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) efree(class_name); /* custom unserialization for objects that are not custom (C: prefix) */ - if (ce->unserialize) { + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; @@ -795,7 +796,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 799 "ext/standard/var_unserializer.c" +#line 800 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -820,7 +821,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 694 "ext/standard/var_unserializer.re" +#line 695 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -828,7 +829,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 832 "ext/standard/var_unserializer.c" +#line 833 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -849,7 +850,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 674 "ext/standard/var_unserializer.re" +#line 675 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -869,7 +870,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 873 "ext/standard/var_unserializer.c" +#line 874 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -890,7 +891,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 645 "ext/standard/var_unserializer.re" +#line 646 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -919,7 +920,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 923 "ext/standard/var_unserializer.c" +#line 924 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -940,7 +941,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 617 "ext/standard/var_unserializer.re" +#line 618 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -968,7 +969,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 972 "ext/standard/var_unserializer.c" +#line 973 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1056,7 +1057,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 607 "ext/standard/var_unserializer.re" +#line 608 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -1066,7 +1067,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1070 "ext/standard/var_unserializer.c" +#line 1071 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1125,22 +1126,22 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 592 "ext/standard/var_unserializer.re" +#line 593 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } return 1; } -#line 1144 "ext/standard/var_unserializer.c" +#line 1145 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1167,7 +1168,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 565 "ext/standard/var_unserializer.re" +#line 566 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1194,7 +1195,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1198 "ext/standard/var_unserializer.c" +#line 1199 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1202,24 +1203,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 558 "ext/standard/var_unserializer.re" +#line 559 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1213 "ext/standard/var_unserializer.c" +#line 1214 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 551 "ext/standard/var_unserializer.re" +#line 552 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1223 "ext/standard/var_unserializer.c" +#line 1224 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1242,7 +1243,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 528 "ext/standard/var_unserializer.re" +#line 529 "ext/standard/var_unserializer.re" { long id; @@ -1265,7 +1266,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1269 "ext/standard/var_unserializer.c" +#line 1270 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1288,7 +1289,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 507 "ext/standard/var_unserializer.re" +#line 508 "ext/standard/var_unserializer.re" { long id; @@ -1309,9 +1310,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1313 "ext/standard/var_unserializer.c" +#line 1314 "ext/standard/var_unserializer.c" } -#line 865 "ext/standard/var_unserializer.re" +#line 866 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 190eb5c3258f1..7f7da7c1ecdc8 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -21,6 +21,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -593,11 +594,11 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } @@ -841,7 +842,7 @@ object ":" uiv ":" ["] { efree(class_name); /* custom unserialization for objects that are not custom (C: prefix) */ - if (ce->unserialize) { + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); if (ret < 0) { return 0; From 472e08577d3726d95101b7c492d2ce26bef8d5f9 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sun, 15 Sep 2013 19:36:58 +0100 Subject: [PATCH 7/9] Add new internal serialize API --- ext/standard/php_var.h | 48 ++++++- ext/standard/var.c | 219 ++++++++++++++++++++++--------- ext/standard/var_unserializer.c | 151 ++++++++++++++++----- ext/standard/var_unserializer.re | 87 +++++++++++- 4 files changed, 403 insertions(+), 102 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index afc5f178e4fcd..a6417b5b4c3b0 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -38,8 +38,47 @@ PHPAPI void php_var_export_ex(zval **struc, int level, smart_str *buf TSRMLS_DC) PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC); + +#define PHP_SERIALIZE_FAILURE (FAILURE) +#define PHP_SERIALIZE_CUSTOM (SUCCESS) +#define PHP_SERIALIZE_OBJECT (SUCCESS + 1) + typedef HashTable* php_serialize_data_t; +/* serialize variable */ +PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); + +/* add object serialization string prefix */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC); + +/* append string that ends the object definition */ +PHPAPI void php_var_serialize_object_end(smart_str *buf); + +/* append null property */ +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key); + +/* append boolean property */ +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value); + +/* append long property */ +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value); + +/* append double property */ +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC); + +/* append string property */ +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value); + +/* append string property */ +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len); + +/* append string property zval */ +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC); + +/* append properties taken from HashTable */ +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC); + + struct php_unserialize_data { void *first; void *last; @@ -49,9 +88,16 @@ struct php_unserialize_data { typedef struct php_unserialize_data* php_unserialize_data_t; -PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t *var_hash TSRMLS_DC); +/* unserialize variable */ PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); +/* unserialize one property (key and value) of the serialized object */ +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); + +/* unserialize all properties of the serialized object and save them to ht */ +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC); + + #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ do { \ /* fprintf(stderr, "SERIALIZE_INIT == lock: %u, level: %u\n", BG(serialize_lock), BG(serialize).level); */ \ diff --git a/ext/standard/var.c b/ext/standard/var.c index c1e7c2f3ee346..4194873d57ccf 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -584,6 +584,20 @@ static inline int php_add_var_hash(HashTable *var_hash, zval *var, void *var_old } /* }}} */ +static inline void php_var_serialize_null(smart_str *buf) /* {{{ */ +{ + smart_str_appendl(buf, "N;", 2); +} +/* }}} */ + +static inline void php_var_serialize_bool(smart_str *buf, long val) /* {{{ */ +{ + smart_str_appendl(buf, "b:", 2); + smart_str_append_long(buf, val); + smart_str_appendc(buf, ';'); +} +/* }}} */ + static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ { smart_str_appendl(buf, "i:", 2); @@ -592,7 +606,21 @@ static inline void php_var_serialize_long(smart_str *buf, long val) /* {{{ */ } /* }}} */ -static inline void php_var_serialize_string(smart_str *buf, char *str, int len) /* {{{ */ +static inline void php_var_serialize_double(smart_str *buf, double val TSRMLS_DC) /* {{{ */ +{ + char *s; + + smart_str_appendl(buf, "d:", 2); + s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); + php_gcvt(val, PG(serialize_precision), '.', 'E', s); + smart_str_appends(buf, s); + smart_str_appendc(buf, ';'); + efree(s); + return; +} +/* }}} */ + +static inline void php_var_serialize_string(smart_str *buf, const char *str, int len) /* {{{ */ { smart_str_appendl(buf, "s:", 2); smart_str_append_long(buf, len); @@ -602,6 +630,55 @@ static inline void php_var_serialize_string(smart_str *buf, char *str, int len) } /* }}} */ +static inline void php_var_serialize_hash_table(smart_str *buf, HashTable *myht, zval **pstruc, zend_bool incomplete_class, HashTable *var_hash TSRMLS_DC) /* {{{ */ +{ + int i; + char *key; + zval **data; + ulong index; + uint key_len; + HashPosition pos; + + zend_hash_internal_pointer_reset_ex(myht, &pos); + for (;; zend_hash_move_forward_ex(myht, &pos)) { + i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); + if (i == HASH_KEY_NON_EXISTENT) { + break; + } + if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { + continue; + } + + switch (i) { + case HASH_KEY_IS_LONG: + php_var_serialize_long(buf, index); + break; + case HASH_KEY_IS_STRING: + php_var_serialize_string(buf, key, key_len - 1); + break; + } + + /* we should still add element even if it's not OK, + * since we already wrote the length of the array before */ + if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS + || !data + || data == pstruc + || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) + ) { + smart_str_appendl(buf, "N;", 2); + } else { + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount++; + } + php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); + if (Z_TYPE_PP(data) == IS_ARRAY) { + Z_ARRVAL_PP(data)->nApplyCount--; + } + } + } +} +/* }}} */ + static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval *struc TSRMLS_DC) /* {{{ */ { PHP_CLASS_ATTRIBUTES; @@ -734,30 +811,20 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var switch (Z_TYPE_P(struc)) { case IS_BOOL: - smart_str_appendl(buf, "b:", 2); - smart_str_append_long(buf, Z_LVAL_P(struc)); - smart_str_appendc(buf, ';'); + php_var_serialize_bool(buf, Z_LVAL_P(struc)); return; case IS_NULL: - smart_str_appendl(buf, "N;", 2); + php_var_serialize_null(buf); return; case IS_LONG: php_var_serialize_long(buf, Z_LVAL_P(struc)); return; - case IS_DOUBLE: { - char *s; - - smart_str_appendl(buf, "d:", 2); - s = (char *) safe_emalloc(PG(serialize_precision), 1, MAX_LENGTH_OF_DOUBLE + 1); - php_gcvt(Z_DVAL_P(struc), PG(serialize_precision), '.', 'E', s); - smart_str_appends(buf, s); - smart_str_appendc(buf, ';'); - efree(s); - return; - } + case IS_DOUBLE: + php_var_serialize_double(buf, Z_DVAL_P(struc) TSRMLS_CC); + return; case IS_STRING: php_var_serialize_string(buf, Z_STRVAL_P(struc), Z_STRLEN_P(struc)); @@ -766,7 +833,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var case IS_OBJECT: { zval *retval_ptr = NULL; zval fname; - int res; + int res, serialize_rc; zend_class_entry *ce = NULL; if (Z_OBJ_HT_P(struc)->get_class_entry) { @@ -778,7 +845,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var unsigned char *serialized_data = NULL; zend_uint serialized_length; - if (ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC) == SUCCESS) { + serialize_rc = ce->serialize(struc, &serialized_data, &serialized_length, (zend_serialize_data *)var_hash TSRMLS_CC); + if (serialize_rc == PHP_SERIALIZE_CUSTOM) { smart_str_appendl(buf, "C:", 2); smart_str_append_long(buf, (int)Z_OBJCE_P(struc)->name_length); smart_str_appendl(buf, ":\"", 2); @@ -789,6 +857,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_appendl(buf, ":{", 2); smart_str_appendl(buf, serialized_data, serialized_length); smart_str_appendc(buf, '}'); + } else if (serialize_rc == PHP_SERIALIZE_OBJECT) { + smart_str_appendl(buf, serialized_data, serialized_length); } else { smart_str_appendl(buf, "N;", 2); } @@ -851,49 +921,7 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, HashTable *var smart_str_append_long(buf, i); smart_str_appendl(buf, ":{", 2); if (i > 0) { - char *key; - zval **data; - ulong index; - uint key_len; - HashPosition pos; - - zend_hash_internal_pointer_reset_ex(myht, &pos); - for (;; zend_hash_move_forward_ex(myht, &pos)) { - i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); - if (i == HASH_KEY_NON_EXISTENT) { - break; - } - if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { - continue; - } - - switch (i) { - case HASH_KEY_IS_LONG: - php_var_serialize_long(buf, index); - break; - case HASH_KEY_IS_STRING: - php_var_serialize_string(buf, key, key_len - 1); - break; - } - - /* we should still add element even if it's not OK, - * since we already wrote the length of the array before */ - if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) != SUCCESS - || !data - || data == &struc - || (Z_TYPE_PP(data) == IS_ARRAY && Z_ARRVAL_PP(data)->nApplyCount > 1) - ) { - smart_str_appendl(buf, "N;", 2); - } else { - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount++; - } - php_var_serialize_intern(buf, *data, var_hash TSRMLS_CC); - if (Z_TYPE_PP(data) == IS_ARRAY) { - Z_ARRVAL_PP(data)->nApplyCount--; - } - } - } + php_var_serialize_hash_table(buf, myht, &struc, incomplete_class, var_hash TSRMLS_CC); } smart_str_appendc(buf, '}'); return; @@ -912,6 +940,75 @@ PHPAPI void php_var_serialize(smart_str *buf, zval **struc, php_serialize_data_t } /* }}} */ +PHPAPI void php_var_serialize_object_start(smart_str *buf, zval *object, zend_uint nprops TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_class_name(buf, object TSRMLS_CC); + smart_str_append_long(buf, nprops); + smart_str_appendl(buf, ":{", 2); +} +/* }}} */ + +PHPAPI void php_var_serialize_object_end(smart_str *buf) /* {{{ */ +{ + smart_str_appendc(buf, '}'); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_null(smart_str *buf, const char *key) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_bool(smart_str *buf, const char *key, int value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_bool(buf, (long) value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_long(smart_str *buf, const char *key, long value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_long(buf, value); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_double(smart_str *buf, const char *key, double value TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_double(buf, value TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_string(smart_str *buf, const char *key, const char *value) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, strlen(value)); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_stringl(smart_str *buf, const char *key, const char *value, int value_len) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_string(buf, value, value_len); +} +/* }}} */ + +PHPAPI void php_var_serialize_property_zval(smart_str *buf, const char *key, zval *value, zend_serialize_data *data TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_string(buf, key, strlen(key)); + php_var_serialize_intern(buf, value, (HashTable *) data TSRMLS_CC); +} +/* }}} */ + +PHPAPI void php_var_serialize_properties(smart_str *buf, HashTable *properties, zend_serialize_data *data TSRMLS_DC) /* {{{ */ +{ + php_var_serialize_hash_table(buf, properties, NULL, 0, (HashTable *) data TSRMLS_CC); +} +/* }}} */ + + /* {{{ proto string serialize(mixed variable) Returns a string representation of variable (which can later be unserialized) */ PHP_FUNCTION(serialize) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index f7546428b1e61..d8ace9591ceab 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.5 */ +/* Generated by re2c 0.13.6 */ #line 1 "ext/standard/var_unserializer.re" /* +----------------------------------------------------------------------+ @@ -23,6 +23,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -226,7 +227,7 @@ static char *unserialize_str(const unsigned char **p, size_t *len, size_t maxlen #define YYMARKER marker -#line 234 "ext/standard/var_unserializer.re" +#line 235 "ext/standard/var_unserializer.re" @@ -379,7 +380,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) 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) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -436,6 +437,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -457,7 +525,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 461 "ext/standard/var_unserializer.c" +#line 529 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -517,9 +585,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 812 "ext/standard/var_unserializer.re" +#line 891 "ext/standard/var_unserializer.re" { return 0; } -#line 523 "ext/standard/var_unserializer.c" +#line 591 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -562,13 +630,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 806 "ext/standard/var_unserializer.re" +#line 885 "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 572 "ext/standard/var_unserializer.c" +#line 640 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -598,7 +666,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 660 "ext/standard/var_unserializer.re" +#line 728 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -742,9 +810,20 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } efree(class_name); + /* custom unserialization for objects that are not custom (C: prefix) */ + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 748 "ext/standard/var_unserializer.c" +#line 827 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -769,7 +848,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 652 "ext/standard/var_unserializer.re" +#line 720 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -777,7 +856,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 781 "ext/standard/var_unserializer.c" +#line 860 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -798,7 +877,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 632 "ext/standard/var_unserializer.re" +#line 700 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -818,7 +897,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 822 "ext/standard/var_unserializer.c" +#line 901 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -839,7 +918,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 603 "ext/standard/var_unserializer.re" +#line 671 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -868,7 +947,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 872 "ext/standard/var_unserializer.c" +#line 951 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -889,7 +968,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 575 "ext/standard/var_unserializer.re" +#line 643 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -917,7 +996,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 921 "ext/standard/var_unserializer.c" +#line 1000 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1005,7 +1084,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 565 "ext/standard/var_unserializer.re" +#line 633 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -1015,7 +1094,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1019 "ext/standard/var_unserializer.c" +#line 1098 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1074,22 +1153,22 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 550 "ext/standard/var_unserializer.re" +#line 618 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } return 1; } -#line 1093 "ext/standard/var_unserializer.c" +#line 1172 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1116,7 +1195,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 523 "ext/standard/var_unserializer.re" +#line 591 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1143,7 +1222,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1147 "ext/standard/var_unserializer.c" +#line 1226 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1151,24 +1230,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 516 "ext/standard/var_unserializer.re" +#line 584 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1162 "ext/standard/var_unserializer.c" +#line 1241 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 509 "ext/standard/var_unserializer.re" +#line 577 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1172 "ext/standard/var_unserializer.c" +#line 1251 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1191,7 +1270,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 486 "ext/standard/var_unserializer.re" +#line 554 "ext/standard/var_unserializer.re" { long id; @@ -1214,7 +1293,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1218 "ext/standard/var_unserializer.c" +#line 1297 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1237,7 +1316,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 465 "ext/standard/var_unserializer.re" +#line 533 "ext/standard/var_unserializer.re" { long id; @@ -1258,9 +1337,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1262 "ext/standard/var_unserializer.c" +#line 1341 "ext/standard/var_unserializer.c" } -#line 814 "ext/standard/var_unserializer.re" +#line 893 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 76c501e1b58c9..0727077a3b7e9 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -21,6 +21,7 @@ #include "php.h" #include "ext/standard/php_var.h" #include "php_incomplete_class.h" +#include "zend_interfaces.h" /* {{{ reference-handling for unserializer: var_* */ #define VAR_ENTRIES_MAX 1024 @@ -383,7 +384,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) 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) { + } else if (ce->unserialize(rval, ce, (const unsigned char*)*p, datalen, (zend_unserialize_data *)var_hash TSRMLS_CC) < 0) { return 0; } @@ -440,6 +441,73 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + while (elements-- > 0) { + zval *key, *value; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(value); + + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(value); + FREE_ZVAL(value); + return 0; + } + + zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &value, sizeof value, NULL); + + zval_dtor(key); + FREE_ZVAL(key); + + if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + (*buf)--; + return 0; + } + } + + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -551,11 +619,11 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) *p = YYCURSOR; INIT_PZVAL(*rval); - if (!strncmp(start + 2, "NAN", 3)) { + if (!strncmp((const char *) (start + 2), "NAN", 3)) { ZVAL_DOUBLE(*rval, php_get_nan()); - } else if (!strncmp(start + 2, "INF", 3)) { + } else if (!strncmp((const char *) (start + 2), "INF", 3)) { ZVAL_DOUBLE(*rval, php_get_inf()); - } else if (!strncmp(start + 2, "-INF", 4)) { + } else if (!strncmp((const char *) (start + 2), "-INF", 4)) { ZVAL_DOUBLE(*rval, -php_get_inf()); } @@ -800,6 +868,17 @@ object ":" uiv ":" ["] { } efree(class_name); + /* custom unserialization for objects that are not custom (C: prefix) */ + if (ce->unserialize && ce->unserialize != zend_user_unserialize) { + int ret = ce->unserialize(rval, ce, (const unsigned char*)*p, max - *p, (zend_unserialize_data *)var_hash TSRMLS_CC); + if (ret < 0) { + return 0; + } + /* In this case the return value from unserialize callback is the number of character left in the buffer */ + (*p) = max - ret; + return finish_nested_data(UNSERIALIZE_PASSTHRU); + } + return object_common2(UNSERIALIZE_PASSTHRU, elements); } From 825f7f313b618b3a48fc180d7203fb55c26146cb Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 5 Oct 2013 17:58:50 +0100 Subject: [PATCH 8/9] Add php_var_unserialize_has_properties to find out the end of unserialized string --- ext/standard/php_var.h | 8 ++- ext/standard/var_unserializer.c | 103 ++++++++++++++++--------------- ext/standard/var_unserializer.re | 43 +++++++------ 3 files changed, 83 insertions(+), 71 deletions(-) diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index a6417b5b4c3b0..78727d3923038 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -91,12 +91,14 @@ typedef struct php_unserialize_data* php_unserialize_data_t; /* unserialize variable */ PHPAPI int php_var_unserialize(zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC); -/* unserialize one property (key and value) of the serialized object */ -PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); +/* whether unserialization finished */ +PHPAPI int php_var_unserialize_has_properties(const unsigned char *buf, zend_uint buf_len); /* unserialize all properties of the serialized object and save them to ht */ -PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC); +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); +/* unserialize one property (key and value) of the serialized object */ +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC); #define PHP_VAR_SERIALIZE_INIT(var_hash_ptr) \ do { \ diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index d8ace9591ceab..3d1b8e4a7bec2 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -437,32 +437,18 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif -PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_has_properties(const unsigned char *buf, zend_uint buf_len) { - const unsigned char *max; - - max = *buf + *buf_len; - - if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { - zval_dtor(key); - return 0; - } - if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { - zval_dtor(key); - zval_dtor(value); - return 0; - } - *buf_len = max - *buf; - return 1; + return buf_len && *buf != '}'; } -PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) { const unsigned char *max; max = *buf + *buf_len; - while (elements-- > 0) { + while (php_var_unserialize_has_properties(*buf, *buf_len)) { zval *key, *value; ALLOC_INIT_ZVAL(key); @@ -494,7 +480,7 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b zval_dtor(key); FREE_ZVAL(key); - if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + if (php_var_unserialize_has_properties(*buf, *buf_len) && *(*buf-1) != ';' && *(*buf-1) != '}') { (*buf)--; return 0; } @@ -504,6 +490,25 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b return 1; } +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -525,7 +530,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 529 "ext/standard/var_unserializer.c" +#line 534 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -585,9 +590,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 891 "ext/standard/var_unserializer.re" +#line 896 "ext/standard/var_unserializer.re" { return 0; } -#line 591 "ext/standard/var_unserializer.c" +#line 596 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -630,13 +635,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 885 "ext/standard/var_unserializer.re" +#line 890 "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 640 "ext/standard/var_unserializer.c" +#line 645 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -666,7 +671,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 728 "ext/standard/var_unserializer.re" +#line 733 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -823,7 +828,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 827 "ext/standard/var_unserializer.c" +#line 832 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -848,7 +853,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 720 "ext/standard/var_unserializer.re" +#line 725 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -856,7 +861,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 860 "ext/standard/var_unserializer.c" +#line 865 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -877,7 +882,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 700 "ext/standard/var_unserializer.re" +#line 705 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -897,7 +902,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 901 "ext/standard/var_unserializer.c" +#line 906 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -918,7 +923,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 671 "ext/standard/var_unserializer.re" +#line 676 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -947,7 +952,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 951 "ext/standard/var_unserializer.c" +#line 956 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -968,7 +973,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 643 "ext/standard/var_unserializer.re" +#line 648 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -996,7 +1001,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 1000 "ext/standard/var_unserializer.c" +#line 1005 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1084,7 +1089,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 633 "ext/standard/var_unserializer.re" +#line 638 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -1094,7 +1099,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1098 "ext/standard/var_unserializer.c" +#line 1103 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1153,7 +1158,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 618 "ext/standard/var_unserializer.re" +#line 623 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -1168,7 +1173,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1172 "ext/standard/var_unserializer.c" +#line 1177 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1195,7 +1200,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 591 "ext/standard/var_unserializer.re" +#line 596 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1222,7 +1227,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1226 "ext/standard/var_unserializer.c" +#line 1231 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1230,24 +1235,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 584 "ext/standard/var_unserializer.re" +#line 589 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1241 "ext/standard/var_unserializer.c" +#line 1246 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 577 "ext/standard/var_unserializer.re" +#line 582 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1251 "ext/standard/var_unserializer.c" +#line 1256 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1270,7 +1275,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 554 "ext/standard/var_unserializer.re" +#line 559 "ext/standard/var_unserializer.re" { long id; @@ -1293,7 +1298,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1297 "ext/standard/var_unserializer.c" +#line 1302 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1316,7 +1321,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 533 "ext/standard/var_unserializer.re" +#line 538 "ext/standard/var_unserializer.re" { long id; @@ -1337,9 +1342,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1341 "ext/standard/var_unserializer.c" +#line 1346 "ext/standard/var_unserializer.c" } -#line 893 "ext/standard/var_unserializer.re" +#line 898 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 0727077a3b7e9..45914bf50418d 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -441,32 +441,18 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, long elements) # pragma optimize("", on) #endif -PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_has_properties(const unsigned char *buf, zend_uint buf_len) { - const unsigned char *max; - - max = *buf + *buf_len; - - if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { - zval_dtor(key); - return 0; - } - if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { - zval_dtor(key); - zval_dtor(value); - return 0; - } - *buf_len = max - *buf; - return 1; + return buf_len && *buf != '}'; } -PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_uint elements, zend_unserialize_data *data TSRMLS_DC) +PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) { const unsigned char *max; max = *buf + *buf_len; - while (elements-- > 0) { + while (php_var_unserialize_has_properties(*buf, *buf_len)) { zval *key, *value; ALLOC_INIT_ZVAL(key); @@ -498,7 +484,7 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b zval_dtor(key); FREE_ZVAL(key); - if (elements && *(*buf-1) != ';' && *(*buf-1) != '}') { + if (php_var_unserialize_has_properties(*buf, *buf_len) && *(*buf-1) != ';' && *(*buf-1) != '}') { (*buf)--; return 0; } @@ -508,6 +494,25 @@ PHPAPI int php_var_unserialize_properties(HashTable *ht, const unsigned char **b return 1; } +PHPAPI int php_var_unserialize_property(zval *key, zval *value, const unsigned char **buf, zend_uint *buf_len, zend_unserialize_data *data TSRMLS_DC) +{ + const unsigned char *max; + + max = *buf + *buf_len; + + if (!php_var_unserialize(&key, buf, max, NULL TSRMLS_CC) || Z_TYPE_P(key) != IS_STRING) { + zval_dtor(key); + return 0; + } + if (!php_var_unserialize(&value, buf, max, (php_unserialize_data_t *) data TSRMLS_CC)) { + zval_dtor(key); + zval_dtor(value); + return 0; + } + *buf_len = max - *buf; + return 1; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; From 13f54c11376e72c966099b6aa2263acb8a9f90ea Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Wed, 30 Oct 2013 20:49:03 +0000 Subject: [PATCH 9/9] Set uninitialized rval as NULL before passed to unserialize --- ext/standard/var_unserializer.c | 61 ++++++++++++++++---------------- ext/standard/var_unserializer.re | 1 + 2 files changed, 32 insertions(+), 30 deletions(-) diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index 3d1b8e4a7bec2..3b416338f6aa7 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -377,6 +377,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) return 0; } + ZVAL_NULL(*rval); if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ce->name); object_init_ex(*rval, ce); @@ -530,7 +531,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 534 "ext/standard/var_unserializer.c" +#line 535 "ext/standard/var_unserializer.c" { YYCTYPE yych; static const unsigned char yybm[] = { @@ -590,9 +591,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy95; yy3: -#line 896 "ext/standard/var_unserializer.re" +#line 897 "ext/standard/var_unserializer.re" { return 0; } -#line 596 "ext/standard/var_unserializer.c" +#line 597 "ext/standard/var_unserializer.c" yy4: yych = *(YYMARKER = ++YYCURSOR); if (yych == ':') goto yy89; @@ -635,13 +636,13 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) goto yy3; yy14: ++YYCURSOR; -#line 890 "ext/standard/var_unserializer.re" +#line 891 "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 645 "ext/standard/var_unserializer.c" +#line 646 "ext/standard/var_unserializer.c" yy16: yych = *++YYCURSOR; goto yy3; @@ -671,7 +672,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 733 "ext/standard/var_unserializer.re" +#line 734 "ext/standard/var_unserializer.re" { size_t len, len2, len3, maxlen; long elements; @@ -828,7 +829,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 832 "ext/standard/var_unserializer.c" +#line 833 "ext/standard/var_unserializer.c" yy25: yych = *++YYCURSOR; if (yych <= ',') { @@ -853,7 +854,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 725 "ext/standard/var_unserializer.re" +#line 726 "ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -861,7 +862,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 865 "ext/standard/var_unserializer.c" +#line 866 "ext/standard/var_unserializer.c" yy32: yych = *++YYCURSOR; if (yych == '+') goto yy33; @@ -882,7 +883,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '{') goto yy18; ++YYCURSOR; -#line 705 "ext/standard/var_unserializer.re" +#line 706 "ext/standard/var_unserializer.re" { long elements = parse_iv(start + 2); /* use iv() not uiv() in order to check data range */ @@ -902,7 +903,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 906 "ext/standard/var_unserializer.c" +#line 907 "ext/standard/var_unserializer.c" yy39: yych = *++YYCURSOR; if (yych == '+') goto yy40; @@ -923,7 +924,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 676 "ext/standard/var_unserializer.re" +#line 677 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -952,7 +953,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 0); return 1; } -#line 956 "ext/standard/var_unserializer.c" +#line 957 "ext/standard/var_unserializer.c" yy46: yych = *++YYCURSOR; if (yych == '+') goto yy47; @@ -973,7 +974,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != '"') goto yy18; ++YYCURSOR; -#line 648 "ext/standard/var_unserializer.re" +#line 649 "ext/standard/var_unserializer.re" { size_t len, maxlen; char *str; @@ -1001,7 +1002,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 1005 "ext/standard/var_unserializer.c" +#line 1006 "ext/standard/var_unserializer.c" yy53: yych = *++YYCURSOR; if (yych <= '/') { @@ -1089,7 +1090,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) } yy63: ++YYCURSOR; -#line 638 "ext/standard/var_unserializer.re" +#line 639 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 use_double: @@ -1099,7 +1100,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL)); return 1; } -#line 1103 "ext/standard/var_unserializer.c" +#line 1104 "ext/standard/var_unserializer.c" yy65: yych = *++YYCURSOR; if (yych <= ',') { @@ -1158,7 +1159,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 623 "ext/standard/var_unserializer.re" +#line 624 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -1173,7 +1174,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1177 "ext/standard/var_unserializer.c" +#line 1178 "ext/standard/var_unserializer.c" yy76: yych = *++YYCURSOR; if (yych == 'N') goto yy73; @@ -1200,7 +1201,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy79; if (yych != ';') goto yy18; ++YYCURSOR; -#line 596 "ext/standard/var_unserializer.re" +#line 597 "ext/standard/var_unserializer.re" { #if SIZEOF_LONG == 4 int digits = YYCURSOR - start - 3; @@ -1227,7 +1228,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 1231 "ext/standard/var_unserializer.c" +#line 1232 "ext/standard/var_unserializer.c" yy83: yych = *++YYCURSOR; if (yych <= '/') goto yy18; @@ -1235,24 +1236,24 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) yych = *++YYCURSOR; if (yych != ';') goto yy18; ++YYCURSOR; -#line 589 "ext/standard/var_unserializer.re" +#line 590 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 1246 "ext/standard/var_unserializer.c" +#line 1247 "ext/standard/var_unserializer.c" yy87: ++YYCURSOR; -#line 582 "ext/standard/var_unserializer.re" +#line 583 "ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 1256 "ext/standard/var_unserializer.c" +#line 1257 "ext/standard/var_unserializer.c" yy89: yych = *++YYCURSOR; if (yych <= ',') { @@ -1275,7 +1276,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy91; if (yych != ';') goto yy18; ++YYCURSOR; -#line 559 "ext/standard/var_unserializer.re" +#line 560 "ext/standard/var_unserializer.re" { long id; @@ -1298,7 +1299,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1302 "ext/standard/var_unserializer.c" +#line 1303 "ext/standard/var_unserializer.c" yy95: yych = *++YYCURSOR; if (yych <= ',') { @@ -1321,7 +1322,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) if (yych <= '9') goto yy97; if (yych != ';') goto yy18; ++YYCURSOR; -#line 538 "ext/standard/var_unserializer.re" +#line 539 "ext/standard/var_unserializer.re" { long id; @@ -1342,9 +1343,9 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) return 1; } -#line 1346 "ext/standard/var_unserializer.c" +#line 1347 "ext/standard/var_unserializer.c" } -#line 898 "ext/standard/var_unserializer.re" +#line 899 "ext/standard/var_unserializer.re" return 0; diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re index 45914bf50418d..8b133b0f75f03 100644 --- a/ext/standard/var_unserializer.re +++ b/ext/standard/var_unserializer.re @@ -381,6 +381,7 @@ static inline int object_custom(UNSERIALIZE_PARAMETER, zend_class_entry *ce) return 0; } + ZVAL_NULL(*rval); if (ce->unserialize == NULL) { zend_error(E_WARNING, "Class %s has no unserializer", ce->name); object_init_ex(*rval, ce);