From: Marcus Boerger Date: Fri, 24 Sep 2004 21:57:19 +0000 (+0000) Subject: - MFH Several serialize/unserialize fixes X-Git-Tag: php-4.3.10RC1~73 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=c3f72d45ecc713fe21f4c15dfea48dd72b233f3d;p=php - MFH Several serialize/unserialize fixes --- diff --git a/ext/standard/incomplete_class.c b/ext/standard/incomplete_class.c index a5f74b1a84..f9a1f0c7ee 100644 --- a/ext/standard/incomplete_class.c +++ b/ext/standard/incomplete_class.c @@ -115,9 +115,6 @@ char *php_lookup_class_name(zval *object, size_t *nlen, zend_bool del TSRMLS_DC) if (nlen) *nlen = Z_STRLEN_PP(val); - - if (del) - zend_hash_del(object_properties, MAGIC_MEMBER, sizeof(MAGIC_MEMBER)); } return (retval); diff --git a/ext/standard/php_incomplete_class.h b/ext/standard/php_incomplete_class.h index 6cf7f5eb99..649f8b7ca5 100644 --- a/ext/standard/php_incomplete_class.h +++ b/ext/standard/php_incomplete_class.h @@ -31,6 +31,7 @@ if (Z_OBJCE_P(struc) == BG(incomplete_class)) { \ class_name = php_lookup_class_name(struc, &name_len, 1 TSRMLS_CC); \ free_class_name = 1; \ + incomplete_class = 1; \ } else { \ class_name = Z_OBJCE_P(struc)->name; \ name_len = Z_OBJCE_P(struc)->name_length; \ @@ -42,7 +43,8 @@ #define PHP_CLASS_ATTRIBUTES \ char *class_name; \ size_t name_len; \ - zend_bool free_class_name = 0 \ + zend_bool free_class_name = 0; \ + zend_bool incomplete_class = 0 #define INCOMPLETE_CLASS "__PHP_Incomplete_Class" #define MAGIC_MEMBER "__PHP_Incomplete_Class_Name" diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 18cf3d7867..d6f569c2aa 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -46,7 +46,7 @@ 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 char **p, const char *max, php_unserialize_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) \ zend_hash_init(&(var_hash), 10, NULL, NULL, 0) diff --git a/ext/standard/tests/file/bug22414.phpt b/ext/standard/tests/file/bug22414.phpt index f6effd272c..db85edd0f0 100644 --- a/ext/standard/tests/file/bug22414.phpt +++ b/ext/standard/tests/file/bug22414.phpt @@ -1,5 +1,7 @@ --TEST-- Bug #22414: passthru() does not read data correctly +--SKIPIF-- + --INI-- safe_mode= output_handler= diff --git a/ext/standard/tests/serialize/001.phpt b/ext/standard/tests/serialize/001.phpt index 811355beb7..958171ace9 100644 --- a/ext/standard/tests/serialize/001.phpt +++ b/ext/standard/tests/serialize/001.phpt @@ -1,7 +1,5 @@ --TEST-- serialize()/unserialize()/var_dump() ---POST-- ---GET-- --FILE-- a = "hallo"; $this->b = "php"; $this->c = "world"; + $this->d = "!"; } function __sleep() @@ -94,9 +97,11 @@ object(t)(1) { __sleep called O:1:"s":2:{s:1:"a";s:5:"hallo";s:1:"c";s:5:"world";} __wakeup called -object(s)(2) { +object(s)(3) { ["a"]=> string(5) "hallo" + ["b"]=> + NULL ["c"]=> string(5) "world" } diff --git a/ext/standard/tests/serialize/002.phpt b/ext/standard/tests/serialize/002.phpt index 7b83c28a63..841e104a6b 100644 --- a/ext/standard/tests/serialize/002.phpt +++ b/ext/standard/tests/serialize/002.phpt @@ -1,36 +1,44 @@ --TEST-- -serialize() (Bug #14293) ---POST-- ---GET-- +Bug #25378 (unserialize() crashes with invalid data) --FILE-- a = 'hello'; - } - - function __sleep() - { - echo "__sleep called\n"; - return array('a','b'); - } -} - -$t = new t(); -$data = serialize($t); -echo "$data\n"; -$t = unserialize($data); -var_dump($t); - +var_dump(unserialize('b:0;')); +var_dump(unserialize('b:1;')); +var_dump(unserialize('i:823;')); +var_dump(unserialize('s:0:"";')); +var_dump(unserialize('s:3:"foo";')); +var_dump(unserialize('a:1:{i:0;s:2:"12";}')); +var_dump(unserialize('a:2:{i:0;a:0:{}i:1;a:0:{}}')); +var_dump(unserialize('a:3:{i:0;s:3:"foo";i:1;s:3:"bar";i:2;s:3:"baz";}')); +var_dump(unserialize('O:8:"stdClass":0:{}')); ?> +===DONE=== --EXPECT-- -__sleep called -O:1:"t":2:{s:1:"a";s:5:"hello";s:1:"b";N;} -object(t)(2) { - ["a"]=> - string(5) "hello" - ["b"]=> - NULL +bool(false) +bool(true) +int(823) +string(0) "" +string(3) "foo" +array(1) { + [0]=> + string(2) "12" +} +array(2) { + [0]=> + array(0) { + } + [1]=> + array(0) { + } +} +array(3) { + [0]=> + string(3) "foo" + [1]=> + string(3) "bar" + [2]=> + string(3) "baz" +} +object(stdClass)(0) { } +===DONE=== diff --git a/ext/standard/tests/serialize/bug14293.phpt b/ext/standard/tests/serialize/bug14293.phpt index 3fca7e406e..ca28bc1853 100644 --- a/ext/standard/tests/serialize/bug14293.phpt +++ b/ext/standard/tests/serialize/bug14293.phpt @@ -25,10 +25,8 @@ var_dump($t); ?> --EXPECTF-- __sleep called - -Notice: serialize(): "b" returned as member variable from __sleep() but does not exist in %sbug14293.php on line %d O:1:"t":2:{s:1:"a";s:5:"hello";s:1:"b";N;} -object(t)#%d (2) { +object(t)(2) { ["a"]=> string(5) "hello" ["b"]=> diff --git a/ext/standard/tests/serialize/bug25378.phpt b/ext/standard/tests/serialize/bug25378.phpt index e59044002f..e865b96e99 100644 --- a/ext/standard/tests/serialize/bug25378.phpt +++ b/ext/standard/tests/serialize/bug25378.phpt @@ -3,7 +3,57 @@ Bug #25378 (unserialize() crashes with invalid data) --FILE-- +===DONE=== --EXPECTF-- -Notice: unserialize(): Error at offset 0 of 8 bytes in %s on line %d +Notice: unserialize(): Error at offset 0 of 8 bytes in %sbug25378.php on line %d bool(false) + +Notice: unserialize(): Error at offset 0 of 5 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 13 of 19 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 14 of 19 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 2 of 22 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 17 of 18 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 24 of 33 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 17 of 33 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 33 of 32 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 2 of 13 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 2 of 11 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 8 of 9 bytes in %sbug25378.php on line %d +bool(false) + +Notice: unserialize(): Error at offset 5 of 10 bytes in %sbug25378.php on line %d +bool(false) +===DONE=== diff --git a/ext/standard/tests/serialize/bug27469.phpt b/ext/standard/tests/serialize/bug27469.phpt index e8d14106a8..a932f6c0fe 100644 --- a/ext/standard/tests/serialize/bug27469.phpt +++ b/ext/standard/tests/serialize/bug27469.phpt @@ -11,17 +11,17 @@ echo serialize($obj)."\n"; var_dump($obj); ?> --EXPECT-- -object(__PHP_Incomplete_Class)#1 (1) { +object(__PHP_Incomplete_Class)(1) { ["__PHP_Incomplete_Class_Name"]=> - string(9) "TestClass" + string(9) "testclass" } -O:9:"TestClass":0:{} -object(__PHP_Incomplete_Class)#1 (1) { +O:9:"testclass":0:{} +object(__PHP_Incomplete_Class)(1) { ["__PHP_Incomplete_Class_Name"]=> - string(9) "TestClass" + string(9) "testclass" } -O:9:"TestClass":0:{} -object(__PHP_Incomplete_Class)#1 (1) { +O:9:"testclass":0:{} +object(__PHP_Incomplete_Class)(1) { ["__PHP_Incomplete_Class_Name"]=> - string(9) "TestClass" + string(9) "testclass" } diff --git a/ext/standard/tests/serialize/bug28325.phpt b/ext/standard/tests/serialize/bug28325.phpt index 7f2bd66371..0a318736c8 100644 --- a/ext/standard/tests/serialize/bug28325.phpt +++ b/ext/standard/tests/serialize/bug28325.phpt @@ -3,13 +3,13 @@ Bug #28325 (Problem in serialisation of circular references) --FILE-- b = new b(); @@ -17,20 +17,20 @@ $a->b->c = new c(); $a->b->c->d = $a; var_dump(unserialize(serialize($a))); ?> ---EXPECTF-- -object(a)#%d (1) { +--EXPECT-- +object(a)(1) { ["b"]=> - object(b)#%d (1) { + object(b)(1) { ["c"]=> - object(c)#%d (1) { + object(c)(1) { ["d"]=> - object(a)#%d (1) { + object(a)(1) { ["b"]=> - object(b)#%d (1) { + object(b)(1) { ["c"]=> - object(c)#%d (1) { + object(c)(1) { ["d"]=> - *RECURSION* + NULL } } } diff --git a/ext/standard/var.c b/ext/standard/var.c index c992d9cefb..ce976c9e34 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -18,8 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: var.c - 1.111 2001/08/06 13:36:08 thies Exp $ */ +/* $Id$ */ /* {{{ includes @@ -63,6 +62,9 @@ PHPAPI void php_var_dump(zval **struc, int level TSRMLS_DC) { HashTable *myht = NULL; zend_object *object = NULL; + int (*php_element_dump_func)(zval**, int, va_list, zend_hash_key*); + + php_element_dump_func = php_array_element_dump; if (level > 1) { php_printf("%*c", level - 1, ' '); @@ -93,17 +95,20 @@ PHPAPI void php_var_dump(zval **struc, int level TSRMLS_DC) return; } php_printf("%sarray(%d) {\n", COMMON, zend_hash_num_elements(myht)); + php_element_dump_func = php_array_element_dump; goto head_done; case IS_OBJECT: object = Z_OBJ_PP(struc); myht = Z_OBJPROP_PP(struc); - if (myht->nApplyCount > 1) { + if (myht && myht->nApplyCount > 1) { PUTS("*RECURSION*\n"); return; } php_printf("%sobject(%s)(%d) {\n", COMMON, Z_OBJCE_PP(struc)->name, zend_hash_num_elements(myht)); head_done: - zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_array_element_dump, 1, level); + if (myht) { + zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_element_dump_func, 1, level); + } if (level > 1) { php_printf("%*c", level-1, ' '); } @@ -203,7 +208,9 @@ PHPAPI void php_debug_zval_dump(zval **struc, int level TSRMLS_DC) myht = Z_OBJPROP_PP(struc); php_printf("%sobject(%s)(%d) refcount(%u){\n", COMMON, Z_OBJCE_PP(struc)->name, zend_hash_num_elements(myht), Z_REFCOUNT_PP(struc)); head_done: - zend_hash_apply_with_arguments(myht, (apply_func_args_t) zval_array_element_dump, 1, level); + if (myht) { + zend_hash_apply_with_arguments(myht, (apply_func_args_t) zval_array_element_dump, 1, level); + } if (level > 1) { php_printf("%*c", level-1, ' '); } @@ -260,13 +267,17 @@ static int php_array_element_export(zval **zv, int num_args, va_list args, zend_ if (hash_key->nKeyLength==0) { /* numeric key */ php_printf("%*c%ld => ", level + 1, ' ', hash_key->h); } else { /* string key */ - char *key; - int key_len; - key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC); - php_printf("%*c'", level + 1, ' '); - PHPWRITE(key, key_len); - php_printf("' => "); - efree(key); + if (va_arg(args, int) && hash_key->arKey[0] == '\0') { + return 0; + } else { + char *key; + int key_len; + key = php_addcslashes(hash_key->arKey, hash_key->nKeyLength - 1, &key_len, 0, "'\\", 2 TSRMLS_CC); + php_printf("%*c'", level + 1, ' '); + PHPWRITE(key, key_len); + php_printf("' => "); + efree(key); + } } php_var_export(zv, level + 2 TSRMLS_CC); PUTS (",\n"); @@ -332,7 +343,9 @@ PHPAPI void php_var_export(zval **struc, int level TSRMLS_DC) php_printf("\n%*c", level - 1, ' '); } php_printf ("class %s {\n", Z_OBJCE_PP(struc)->name); - zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_object_element_export, 1, level); + if (myht) { + zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_object_element_export, 1, level); + } if (level > 1) { php_printf("%*c", level - 1, ' '); } @@ -419,7 +432,7 @@ static inline void php_var_serialize_string(smart_str *buf, char *str, int len) smart_str_appendl(buf, "\";", 2); } -static inline void php_var_serialize_class_name(smart_str *buf, zval **struc TSRMLS_DC) +static inline zend_bool php_var_serialize_class_name(smart_str *buf, zval **struc TSRMLS_DC) { PHP_CLASS_ATTRIBUTES; @@ -430,16 +443,21 @@ static inline void php_var_serialize_class_name(smart_str *buf, zval **struc TSR smart_str_appendl(buf, class_name, name_len); smart_str_appendl(buf, "\":", 2); PHP_CLEANUP_CLASS_ATTRIBUTES(); + return incomplete_class; } static void php_var_serialize_class(smart_str *buf, zval **struc, zval *retval_ptr, HashTable *var_hash TSRMLS_DC) { int count; + zend_bool incomplete_class; - php_var_serialize_class_name(buf, struc TSRMLS_CC); + incomplete_class = php_var_serialize_class_name(buf, struc TSRMLS_CC); /* count after serializing name, since php_var_serialize_class_name changes the count if the variable is incomplete class */ count = zend_hash_num_elements(HASH_OF(retval_ptr)); + if (incomplete_class) { + --count; + } smart_str_append_long(buf, count); smart_str_appendl(buf, ":{", 2); @@ -463,6 +481,9 @@ static void php_var_serialize_class(smart_str *buf, zval **struc, zval *retval_p if (i == HASH_KEY_NON_EXISTANT) break; + if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { + continue; + } zend_hash_get_current_data_ex(HASH_OF(retval_ptr), (void **) &name, &pos); @@ -475,13 +496,12 @@ static void php_var_serialize_class(smart_str *buf, zval **struc, zval *retval_p smart_str_appendl(buf,"N;", 2); continue; } - - php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name)); - if (zend_hash_find(Z_OBJPROP_PP(struc), Z_STRVAL_PP(name), Z_STRLEN_PP(name) + 1, (void *) &d) == SUCCESS) { + php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name)); php_var_serialize_intern(buf, d, var_hash TSRMLS_CC); } else { + php_var_serialize_string(buf, Z_STRVAL_PP(name), Z_STRLEN_PP(name)); php_var_serialize_intern(buf, &nvalp, var_hash TSRMLS_CC); } } @@ -496,13 +516,19 @@ static void php_var_serialize_intern(smart_str *buf, zval **struc, HashTable *va ulong *var_already; HashTable *myht; - if(var_hash - && php_add_var_hash(var_hash, *struc, (void *) &var_already) == FAILURE - && (*struc)->is_ref) { + if (var_hash + && php_add_var_hash(var_hash, *struc, (void *) &var_already) == FAILURE) { + if((*struc)->is_ref) { smart_str_appendl(buf, "R:", 2); smart_str_append_long(buf, *var_already); smart_str_appendc(buf, ';'); return; + } else if(Z_TYPE_PP(struc) == IS_OBJECT) { + smart_str_appendl(buf, "r:", 2); + smart_str_append_long(buf, *var_already); + smart_str_appendc(buf, ';'); + return; + } } switch (Z_TYPE_PP(struc)) { @@ -539,6 +565,7 @@ static void php_var_serialize_intern(smart_str *buf, zval **struc, HashTable *va zval fname; int res; + if(Z_OBJCE_PP(struc) != PHP_IC_ENTRY) { INIT_PZVAL(&fname); ZVAL_STRINGL(&fname, "__sleep", sizeof("__sleep") - 1, 0); res = call_user_function_ex(CG(function_table), struc, &fname, @@ -562,20 +589,27 @@ static void php_var_serialize_intern(smart_str *buf, zval **struc, HashTable *va } return; } + } + if (retval_ptr) zval_ptr_dtor(&retval_ptr); /* fall-through */ } - case IS_ARRAY: - myht = HASH_OF(*struc); + case IS_ARRAY: { + zend_bool incomplete_class = 0; if (Z_TYPE_PP(struc) == IS_ARRAY) { smart_str_appendl(buf, "a:", 2); + myht = HASH_OF(*struc); } else { - php_var_serialize_class_name(buf, struc TSRMLS_CC); + incomplete_class = php_var_serialize_class_name(buf, struc TSRMLS_CC); + myht = Z_OBJPROP_PP(struc); } /* count after serializing name, since php_var_serialize_class_name changes the count if the variable is incomplete class */ - i = zend_hash_num_elements(myht); + i = myht ? zend_hash_num_elements(myht) : 0; + if (i > 0 && incomplete_class) { + --i; + } smart_str_append_long(buf, i); smart_str_appendl(buf, ":{", 2); if (i > 0) { @@ -592,6 +626,10 @@ static void php_var_serialize_intern(smart_str *buf, zval **struc, HashTable *va if (i == HASH_KEY_NON_EXISTANT) break; + if (incomplete_class && strcmp(key, MAGIC_MEMBER) == 0) { + continue; + } + switch (i) { case HASH_KEY_IS_LONG: php_var_serialize_long(buf, index); @@ -615,6 +653,7 @@ static void php_var_serialize_intern(smart_str *buf, zval **struc, HashTable *va } smart_str_appendc(buf, '}'); return; + } default: smart_str_appendl(buf, "i:0;", 4); return; @@ -671,7 +710,7 @@ PHP_FUNCTION(unserialize) } if (Z_TYPE_PP(buf) == IS_STRING) { - const char *p = Z_STRVAL_PP(buf); + const unsigned char *p = (unsigned char*)Z_STRVAL_PP(buf); if (Z_STRLEN_PP(buf) == 0) { RETURN_FALSE; @@ -681,7 +720,7 @@ PHP_FUNCTION(unserialize) if (!php_var_unserialize(&return_value, &p, p + Z_STRLEN_PP(buf), &var_hash TSRMLS_CC)) { PHP_VAR_UNSERIALIZE_DESTROY(var_hash); zval_dtor(return_value); - php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %d of %d bytes", p - Z_STRVAL_PP(buf), Z_STRLEN_PP(buf)); + php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - Z_STRVAL_PP(buf)), Z_STRLEN_PP(buf)); RETURN_FALSE; } PHP_VAR_UNSERIALIZE_DESTROY(var_hash); diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c index d1a006f2bb..65165b9bd2 100644 --- a/ext/standard/var_unserializer.c +++ b/ext/standard/var_unserializer.c @@ -1,5 +1,24 @@ -/* Generated by re2c 0.9.2 on Sat Mar 27 01:58:46 2004 */ +/* Generated by re2c 0.9.4 on Fri Sep 24 23:45:23 2004 */ #line 1 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +/* + +----------------------------------------------------------------------+ + | PHP Version 4 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2003 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 2.02 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available at through the world-wide-web at | + | http://www.php.net/license/2_02.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Authors: Sascha Schumann | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ #include "php.h" #include "ext/standard/php_var.h" @@ -92,12 +111,12 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx) #define YYMARKER marker -#line 99 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 118 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" -static inline int parse_iv2(const char *p, const char **q) +static inline int parse_iv2(const unsigned char *p, const unsigned char **q) { char cursor; int result = 0; @@ -112,7 +131,7 @@ static inline int parse_iv2(const char *p, const char **q) } while (1) { - cursor = *p; + cursor = (char)*p; if (cursor >= '0' && cursor <= '9') { result = result * 10 + cursor - '0'; } else { @@ -125,12 +144,34 @@ static inline int parse_iv2(const char *p, const char **q) return result; } -static inline int parse_iv(const char *p) +static inline int parse_iv(const unsigned char *p) { return parse_iv2(p, NULL); } -#define UNSERIALIZE_PARAMETER zval **rval, const char **p, const char *max, php_unserialize_data_t *var_hash TSRMLS_DC +/* no need to check for length - re2c already did */ +static inline size_t parse_uiv(const unsigned char *p) +{ + unsigned char cursor; + size_t result = 0; + + if (*p == '+') { + p++; + } + + while (1) { + cursor = *p; + if (cursor >= '0' && cursor <= '9') { + result = result * 10 + (size_t)(cursor - (unsigned char)'0'); + } else { + break; + } + p++; + } + return result; +} + +#define UNSERIALIZE_PARAMETER zval **rval, const unsigned char **p, const unsigned char *max, php_unserialize_data_t *var_hash TSRMLS_DC #define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements) @@ -146,6 +187,12 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int 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(data); if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { @@ -163,11 +210,15 @@ static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int case IS_STRING: zend_hash_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); break; - } zval_dtor(key); FREE_ZVAL(key); + + if (elements && *(*p-1) != ';' && *(*p-1) != '}') { + (*p)--; + return 0; + } } return 1; @@ -216,6 +267,20 @@ static inline int object_common2(UNSERIALIZE_PARAMETER, int elements) } +static char *str_tolower_copy(char *dest, const char *source, unsigned int length) +{ + register unsigned char *str = (unsigned char*)source; + register unsigned char *result = (unsigned char*)dest; + register unsigned char *end = str + length; + + while (str < end) { + *result++ = tolower((int)*str++); + } + *result = *end; + + return dest; +} + PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) { const unsigned char *cursor, *limit, *marker, *start; @@ -232,7 +297,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) -#line 7 "re2c-output.c" +#line 7 "" { YYCTYPE yych; unsigned int yyaccept; @@ -310,7 +375,7 @@ yy0: goto yy15; } else { if(yych <= '}') goto yy13; - if(yych <= '\277') goto yy15; + if(yych <= 0xBF) goto yy15; goto yy2; } } @@ -321,14 +386,14 @@ yy2: YYCURSOR = YYMARKER; } yy3: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); - if(yych == ':') goto yy82; + if(yych == ':') goto yy80; goto yy4; yy4: -#line 429 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 511 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { return 0; } -#line 101 "re2c-output.c" +#line 101 "" yy5: yych = *++YYCURSOR; - if(yych == ';') goto yy80; + if(yych == ';') goto yy78; goto yy4; yy6: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); @@ -358,16 +423,16 @@ yy12: yyaccept = 0; yych = *(YYMARKER = ++YYCURSOR); if(yych == ':') goto yy16; goto yy4; -yy13: yych = *++YYCURSOR; +yy13: ++YYCURSOR; goto yy14; yy14: -#line 423 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 505 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { /* this is the case where we have less data than planned */ - zend_error(E_NOTICE, "Unexpected end of serialized data"); + 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 142 "re2c-output.c" +#line 142 "" yy15: yych = *++YYCURSOR; goto yy4; yy16: yych = *++YYCURSOR; @@ -387,14 +452,13 @@ yy19: if(yybm[0+yych] & 128) goto yy18; yy20: yych = *++YYCURSOR; if(yych != '"') goto yy2; goto yy21; -yy21: yych = *++YYCURSOR; +yy21: ++YYCURSOR; goto yy22; yy22: -#line 349 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 424 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { - int len; + size_t len, len2, maxlen; int elements; - int len2; char *class_name; zend_class_entry *ce; int incomplete_class = 0; @@ -405,20 +469,30 @@ yy22: zval *arg_func_name; INIT_PZVAL(*rval); - len2 = len = parse_iv(start + 2); - if (len == 0) + len2 = len = parse_uiv(start + 2); + maxlen = max - YYCURSOR; + if (maxlen < len || len == 0) { + *p = start + 2; return 0; + } + + class_name = (char*)YYCURSOR; - class_name = estrndup(YYCURSOR, len); YYCURSOR += len; - while (len-- > 0) { - if (class_name[len] >= 'A' && class_name[len] <= 'Z') { - class_name[len] = class_name[len] - 'A' + 'a'; - } + if (*(YYCURSOR) != '"') { + *p = YYCURSOR; + return 0; } - - if (zend_hash_find(CG(class_table), class_name, len2 + 1, (void **) &ce) != SUCCESS) { + if (*(YYCURSOR+1) != ':') { + *p = YYCURSOR+1; + return 0; + } + + class_name = str_tolower_copy((char *)emalloc(len+1), class_name, len); + class_name[len] = '\0'; + + if (zend_hash_find(CG(class_table), class_name, len + 1, (void **) &ce) != SUCCESS) { if ((PG(unserialize_callback_func) == NULL) || (PG(unserialize_callback_func)[0] == '\0')) { incomplete_class = 1; ce = PHP_IC_ENTRY; @@ -435,7 +509,7 @@ yy22: incomplete_class = 1; ce = PHP_IC_ENTRY; } else { - if (zend_hash_find(CG(class_table), class_name, len2 + 1, (void **) &ce) != SUCCESS) { + if (zend_hash_find(CG(class_table), class_name, len + 1, (void **) &ce) != SUCCESS) { zend_error(E_WARNING, "'unserialize_callback_func' (%s) hasn't defined the class it was called for", user_func->value.str.val); incomplete_class = 1; ce = PHP_IC_ENTRY; @@ -443,7 +517,6 @@ yy22: #ifdef ZEND_ENGINE_2 ce = *(zend_class_entry **)ce; /* Bad hack, TBF! */ #endif - efree(class_name); } } } @@ -451,7 +524,6 @@ yy22: #ifdef ZEND_ENGINE_2 ce = *(zend_class_entry **)ce; /* Bad hack, TBF! */ #endif - efree(class_name); } *p = YYCURSOR; @@ -459,12 +531,12 @@ yy22: if (incomplete_class) { php_store_class_name(*rval, class_name, len2 TSRMLS_CC); - efree(class_name); } + efree(class_name); return object_common2(UNSERIALIZE_PASSTHRU, elements); } -#line 239 "re2c-output.c" +#line 247 "" yy23: yych = *++YYCURSOR; if(yych <= ','){ if(yych != '+') goto yy2; @@ -490,10 +562,10 @@ yy26: if(yych <= '/') goto yy2; yy27: yych = *++YYCURSOR; if(yych != '"') goto yy2; goto yy28; -yy28: yych = *++YYCURSOR; +yy28: ++YYCURSOR; goto yy29; yy29: -#line 341 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 416 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { INIT_PZVAL(*rval); @@ -501,7 +573,7 @@ yy29: return object_common2(UNSERIALIZE_PASSTHRU, object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR)); } -#line 276 "re2c-output.c" +#line 285 "" yy30: yych = *++YYCURSOR; if(yych == '+') goto yy31; if(yych <= '/') goto yy2; @@ -522,10 +594,10 @@ yy33: if(yych <= '/') goto yy2; yy34: yych = *++YYCURSOR; if(yych != '{') goto yy2; goto yy35; -yy35: yych = *++YYCURSOR; +yy35: ++YYCURSOR; goto yy36; yy36: -#line 323 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 398 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { int elements = parse_iv(start + 2); @@ -543,7 +615,7 @@ yy36: return finish_nested_data(UNSERIALIZE_PASSTHRU); } -#line 318 "re2c-output.c" +#line 328 "" yy37: yych = *++YYCURSOR; if(yych == '+') goto yy38; if(yych <= '/') goto yy2; @@ -564,30 +636,38 @@ yy40: if(yych <= '/') goto yy2; yy41: yych = *++YYCURSOR; if(yych != '"') goto yy2; goto yy42; -yy42: yych = *++YYCURSOR; +yy42: ++YYCURSOR; goto yy43; yy43: -#line 303 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 370 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { - int len; + size_t len, maxlen; char *str; - len = parse_iv(start + 2); + len = parse_uiv(start + 2); + maxlen = max - YYCURSOR; + if (maxlen < len) { + *p = start + 2; + return 0; + } + + str = (char*)YYCURSOR; - if (len == 0) { - str = empty_string; - } else { - str = estrndup(YYCURSOR, len); + YYCURSOR += len; + + if (*(YYCURSOR) != '"') { + *p = YYCURSOR; + return 0; } - YYCURSOR += len + 2; + YYCURSOR += 2; *p = YYCURSOR; INIT_PZVAL(*rval); - ZVAL_STRINGL(*rval, str, len, 0); + ZVAL_STRINGL(*rval, str, len, 1); return 1; } -#line 362 "re2c-output.c" +#line 381 "" yy44: yych = *++YYCURSOR; if(yych <= '/'){ if(yych <= ','){ @@ -673,17 +753,17 @@ yy53: if(yych <= ';'){ goto yy2; } } -yy54: yych = *++YYCURSOR; +yy54: ++YYCURSOR; goto yy55; yy55: -#line 296 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 363 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_DOUBLE(*rval, atof(start + 2)); return 1; } -#line 458 "re2c-output.c" +#line 479 "" yy56: yych = *++YYCURSOR; if(yych <= ','){ if(yych != '+') goto yy2; @@ -740,10 +820,10 @@ yy63: yych = *++YYCURSOR; yy64: yych = *++YYCURSOR; if(yych != ';') goto yy2; goto yy65; -yy65: yych = *++YYCURSOR; +yy65: ++YYCURSOR; goto yy66; yy66: -#line 279 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 346 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); @@ -760,7 +840,7 @@ yy66: #endif return 1; } -#line 535 "re2c-output.c" +#line 558 "" yy67: yych = *++YYCURSOR; if(yych == 'N') goto yy64; goto yy2; @@ -786,87 +866,72 @@ yy71: if(yych <= '/') goto yy2; if(yych <= '9') goto yy70; if(yych != ';') goto yy2; goto yy72; -yy72: yych = *++YYCURSOR; +yy72: ++YYCURSOR; goto yy73; yy73: -#line 272 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 339 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_LONG(*rval, parse_iv(start + 2)); return 1; } -#line 571 "re2c-output.c" +#line 595 "" yy74: yych = *++YYCURSOR; - if(yych <= ','){ - if(yych != '+') goto yy2; - goto yy75; - } else { - if(yych <= '-') goto yy75; - if(yych <= '/') goto yy2; - if(yych <= '9') goto yy76; - goto yy2; - } -yy75: yych = *++YYCURSOR; if(yych <= '/') goto yy2; - if(yych >= ':') goto yy2; + if(yych >= '2') goto yy2; + goto yy75; +yy75: yych = *++YYCURSOR; + if(yych != ';') goto yy2; goto yy76; yy76: ++YYCURSOR; - if(YYLIMIT == YYCURSOR) YYFILL(1); - yych = *YYCURSOR; goto yy77; -yy77: if(yych <= '/') goto yy2; - if(yych <= '9') goto yy76; - if(yych != ';') goto yy2; - goto yy78; -yy78: yych = *++YYCURSOR; - goto yy79; -yy79: -#line 265 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +yy77: +#line 332 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_BOOL(*rval, parse_iv(start + 2)); return 1; } -#line 604 "re2c-output.c" -yy80: yych = *++YYCURSOR; - goto yy81; -yy81: -#line 258 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 613 "" +yy78: ++YYCURSOR; + goto yy79; +yy79: +#line 325 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { *p = YYCURSOR; INIT_PZVAL(*rval); ZVAL_NULL(*rval); return 1; } -#line 615 "re2c-output.c" -yy82: yych = *++YYCURSOR; +#line 624 "" +yy80: yych = *++YYCURSOR; if(yych <= ','){ if(yych != '+') goto yy2; - goto yy83; + goto yy81; } else { - if(yych <= '-') goto yy83; + if(yych <= '-') goto yy81; if(yych <= '/') goto yy2; - if(yych <= '9') goto yy84; + if(yych <= '9') goto yy82; goto yy2; } -yy83: yych = *++YYCURSOR; +yy81: yych = *++YYCURSOR; if(yych <= '/') goto yy2; if(yych >= ':') goto yy2; - goto yy84; -yy84: ++YYCURSOR; + goto yy82; +yy82: ++YYCURSOR; if(YYLIMIT == YYCURSOR) YYFILL(1); yych = *YYCURSOR; - goto yy85; -yy85: if(yych <= '/') goto yy2; - if(yych <= '9') goto yy84; + goto yy83; +yy83: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy82; if(yych != ';') goto yy2; - goto yy86; -yy86: yych = *++YYCURSOR; - goto yy87; -yy87: -#line 239 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" + goto yy84; +yy84: ++YYCURSOR; + goto yy85; +yy85: +#line 304 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" { int id; @@ -878,16 +943,18 @@ yy87: return 0; } + if (*rval != NULL) { zval_ptr_dtor(rval); + } *rval = *rval_ref; (*rval)->refcount++; (*rval)->is_ref = 1; return 1; } -#line 660 "re2c-output.c" +#line 672 "" } -#line 431 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" +#line 513 "/usr/src/PHP_4_3_0/ext/standard/var_unserializer.re" return 0;