diff options
author | Sascha Schumann <sas@php.net> | 2001-11-10 21:18:34 +0000 |
---|---|---|
committer | Sascha Schumann <sas@php.net> | 2001-11-10 21:18:34 +0000 |
commit | f341f630d3fe6fe669f6a4cbf176f7a5e6f3f4db (patch) | |
tree | 3f7fbe4a27171ecd4da8da070d083be12aac5fc5 /ext | |
parent | 88c6758d4e326a9714e0bfccd3309c3e5a282ef9 (diff) | |
download | php-git-f341f630d3fe6fe669f6a4cbf176f7a5e6f3f4db.tar.gz |
Rewrite of unserializer which should be more maintainable and extensible.
Changes pass `make test´ and a couple of custom tests.
Enjoy.
Diffstat (limited to 'ext')
-rw-r--r-- | ext/session/php_session.h | 4 | ||||
-rw-r--r-- | ext/session/session.c | 6 | ||||
-rw-r--r-- | ext/standard/Makefile.in | 6 | ||||
-rw-r--r-- | ext/standard/php_var.h | 36 | ||||
-rw-r--r-- | ext/standard/var.c | 244 | ||||
-rw-r--r-- | ext/standard/var_unserializer.c | 635 | ||||
-rw-r--r-- | ext/standard/var_unserializer.re | 361 |
7 files changed, 1022 insertions, 270 deletions
diff --git a/ext/session/php_session.h b/ext/session/php_session.h index 5d4f0ca5e8..f0c245ea9d 100644 --- a/ext/session/php_session.h +++ b/ext/session/php_session.h @@ -19,6 +19,8 @@ #ifndef PHP_SESSION_H #define PHP_SESSION_H +#include "ext/standard/php_var.h" + #define PS_OPEN_ARGS void **mod_data, const char *save_path, const char *session_name #define PS_CLOSE_ARGS void **mod_data #define PS_READ_ARGS void **mod_data, const char *key, char **val, int *vallen @@ -148,7 +150,7 @@ typedef struct ps_serializer_struct { PHPAPI void session_adapt_url(const char *, size_t, char **, size_t * TSRMLS_DC); -void php_set_session_var(char *name, size_t namelen, zval *state_val,HashTable *var_hash TSRMLS_DC); +void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC); int php_get_session_var(char *name, size_t namelen, zval ***state_var TSRMLS_DC); int php_session_register_module(ps_module *); diff --git a/ext/session/session.c b/ext/session/session.c index ff9be2052e..2a54c4c708 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -259,7 +259,7 @@ typedef struct { #define MAX_STR 512 -void php_set_session_var(char *name, size_t namelen, zval *state_val,HashTable *var_hash TSRMLS_DC) +void php_set_session_var(char *name, size_t namelen, zval *state_val, php_unserialize_data_t *var_hash TSRMLS_DC) { if (PG(register_globals)) { @@ -344,7 +344,7 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) zval *current; int namelen; int has_value; - php_serialize_data_t var_hash; + php_unserialize_data_t var_hash; PHP_VAR_UNSERIALIZE_INIT(var_hash); @@ -411,7 +411,7 @@ PS_SERIALIZER_DECODE_FUNC(php) zval *current; int namelen; int has_value; - php_serialize_data_t var_hash; + php_unserialize_data_t var_hash; PHP_VAR_UNSERIALIZE_INIT(var_hash); diff --git a/ext/standard/Makefile.in b/ext/standard/Makefile.in index fdf2b59830..8a9cd780ac 100644 --- a/ext/standard/Makefile.in +++ b/ext/standard/Makefile.in @@ -8,11 +8,15 @@ LTLIBRARY_SOURCES=\ parsedate.c quot_print.c rand.c reg.c soundex.c string.c scanf.c \ syslog.c type.c uniqid.c url.c url_scanner.c var.c versioning.c assert.c \ strnatcmp.c levenshtein.c incomplete_class.c url_scanner_ex.c \ - ftp_fopen_wrapper.c http_fopen_wrapper.c php_fopen_wrapper.c credits.c + ftp_fopen_wrapper.c http_fopen_wrapper.c php_fopen_wrapper.c credits.c \ + var_unserializer.c include $(top_srcdir)/build/dynlib.mk parsedate.c: $(srcdir)/parsedate.y +$(srcdir)/var_unserializer.c: $(srcdir)/var_unserializer.re + re2c -b $(srcdir)/var_unserializer.re > $@ + $(srcdir)/url_scanner_ex.c: $(srcdir)/url_scanner_ex.re re2c -b $(srcdir)/url_scanner_ex.re > $@ diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index 6336e0fe8e..aa5e003955 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -32,8 +32,14 @@ void php_var_dump(zval **struc, int level TSRMLS_DC); /* typdef HashTable php_serialize_data_t; */ #define php_serialize_data_t HashTable +struct php_unserialize_data { + void *first; +}; + +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_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); #define PHP_VAR_SERIALIZE_INIT(var_hash) \ zend_hash_init(&(var_hash), 10, NULL, NULL, 0) @@ -41,30 +47,16 @@ PHPAPI int php_var_unserialize(zval **rval, const char **p, const char *max, php zend_hash_destroy(&(var_hash)) #define PHP_VAR_UNSERIALIZE_INIT(var_hash) \ - zend_hash_init(&(var_hash), 10, NULL, NULL, 0) + (var_hash).first = 0 #define PHP_VAR_UNSERIALIZE_DESTROY(var_hash) \ - zend_hash_destroy(&(var_hash)) + var_destroy(&(var_hash)) -#define PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash, ozval, nzval) \ -if (var_hash) { \ - HashPosition pos; \ - zval **zval_ref; \ - zend_hash_internal_pointer_reset_ex(var_hash, &pos); \ - while (zend_hash_get_current_data_ex(var_hash, (void **) &zval_ref, &pos) == SUCCESS) { \ - if (*zval_ref == ozval) { \ - char *string_key; \ - uint str_key_len; \ - ulong num_key; \ - \ - zend_hash_get_current_key_ex(var_hash, &string_key, &str_key_len, &num_key, 1, &pos); \ - /* this is our hash and it _will_ be number indexed! */ \ - zend_hash_index_update(var_hash, num_key, &nzval, sizeof(zval *), NULL); \ - break; \ - } \ - zend_hash_move_forward_ex(var_hash, &pos); \ - } \ -} +void var_replace(php_unserialize_data_t *var_hash, zval *ozval, zval **nzval); +void var_destroy(php_unserialize_data_t *var_hash); +#define PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash, ozval, nzval) \ + var_replace((var_hash), (ozval), &(nzval)) + PHPAPI zend_class_entry *php_create_empty_class(char *class_name, int len); #endif /* PHP_VAR_H */ diff --git a/ext/standard/var.c b/ext/standard/var.c index 5b11a5247f..5e865cf29c 100644 --- a/ext/standard/var.c +++ b/ext/standard/var.c @@ -362,249 +362,7 @@ PHPAPI void php_var_serialize(smart_str *buf, zval **struc, HashTable *var_hash } /* }}} */ -/* {{{ php_var_unserialize */ -PHPAPI int php_var_unserialize(zval **rval, const char **p, const char *max, HashTable *var_hash TSRMLS_DC) -{ - const char *q; - char *str; - int i; - char cur; - ulong id; - HashTable *myht; - zval **rval_ref; - - if (var_hash && **p != 'R') { /* references aren't counted by serializer! */ - zend_hash_next_index_insert(var_hash, rval, sizeof(*rval), NULL); - } - - switch (cur = **p) { - case 'R': - if (*((*p) + 1) != ':') { - return 0; - } - q = *p; - while (**p && **p != ';') { - (*p)++; - } - if (**p != ';') { - return 0; - } - (*p)++; - id = atol(q + 2)-1; /* count starts with 1 */ - if (!var_hash) { - return 0; - } - if (zend_hash_index_find(var_hash, id, (void *)&rval_ref) != SUCCESS) { - return 0; - } - zval_ptr_dtor(rval); - *rval = *rval_ref; - (*rval)->refcount++; - (*rval)->is_ref = 1; - return 1; - - case 'N': - if (*((*p) + 1) != ';') { - return 0; - } - (*p)++; - INIT_PZVAL(*rval); - ZVAL_NULL(*rval); - (*p)++; - return 1; - - case 'b': /* bool */ - case 'i': - if (*((*p) + 1) != ':') { - return 0; - } - q = *p; - while (**p && **p != ';') { - (*p)++; - } - if (**p != ';') { - return 0; - } - (*p)++; - INIT_PZVAL(*rval); - if (cur == 'b') { - ZVAL_BOOL(*rval, atol(q + 2)); - } else { - ZVAL_LONG(*rval, atol(q + 2)); - } - return 1; - - case 'd': - if (*((*p) + 1) != ':') { - return 0; - } - q = *p; - while (**p && **p != ';') { - (*p)++; - } - if (**p != ';') { - return 0; - } - (*p)++; - INIT_PZVAL(*rval); - ZVAL_DOUBLE(*rval, atof(q + 2)); - return 1; - - case 's': - if (*((*p) + 1) != ':') { - return 0; - } - (*p) += 2; - q = *p; - while (**p && **p != ':') { - (*p)++; - } - if (**p != ':') { - return 0; - } - i = atoi(q); - if (i < 0 || (*p + 3 + i) > max || *((*p) + 1) != '\"' || - *((*p) + 2 + i) != '\"' || *((*p) + 3 + i) != ';') { - return 0; - } - (*p) += 2; - - if (i == 0) { - str = empty_string; - } else { - str = estrndup(*p, i); - } - (*p) += i + 2; - INIT_PZVAL(*rval); - ZVAL_STRINGL(*rval, str, i, 0); - return 1; - - case 'a': - case 'o': - case 'O': { - zend_bool incomplete_class = 0; - char *class_name = NULL; - size_t name_len = 0; - int pi; - - INIT_PZVAL(*rval); - - if (cur == 'a') { - Z_TYPE_PP(rval) = IS_ARRAY; - ALLOC_HASHTABLE(Z_ARRVAL_PP(rval)); - myht = Z_ARRVAL_PP(rval); - } else { - zend_class_entry *ce; - - if (cur == 'O') { /* php4 serialized - we get the class-name */ - if (*((*p) + 1) != ':') { - return 0; - } - (*p) += 2; - q = *p; - while (**p && **p != ':') { - (*p)++; - } - if (**p != ':') { - return 0; - } - name_len = i = atoi(q); - if (i < 0 || (*p + 3 + i) > max || *((*p) + 1) != '\"' || - *((*p) + 2 + i) != '\"' || *((*p) + 3 + i) != ':') { - return 0; - } - (*p) += 2; - class_name = emalloc(i + 1); - for(pi=0;pi<i;pi++) { - class_name[pi] = tolower((*p)[pi]); - } - class_name[i] = 0; - (*p) += i; - - if (zend_hash_find(EG(class_table), class_name, i+1, (void **) &ce)==FAILURE) { - incomplete_class = 1; - ce = PHP_IC_ENTRY; - } - } else { /* old php 3.0 data 'o' */ - ce = &zend_standard_class_def; - } - - object_init_ex(*rval, ce); - myht = Z_OBJPROP_PP(rval); - - if (incomplete_class) - php_store_class_name(*rval, class_name, name_len); - - if (class_name) - efree(class_name); - } - - (*p) += 2; - i = atoi(*p); - - if (cur == 'a') { /* object_init_ex will init the HashTable for objects! */ - zend_hash_init(myht, i + 1, NULL, ZVAL_PTR_DTOR, 0); - } - - while (**p && **p != ':') { - (*p)++; - } - if (**p != ':' || *((*p) + 1) != '{') { - return 0; - } - for ((*p) += 2; **p && **p != '}' && i > 0; i--) { - zval *key; - zval *data; - - ALLOC_INIT_ZVAL(key); - ALLOC_INIT_ZVAL(data); - - if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { - zval_dtor(key); - FREE_ZVAL(key); - FREE_ZVAL(data); - return 0; - } - if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { - zval_dtor(key); - FREE_ZVAL(key); - zval_dtor(data); - FREE_ZVAL(data); - return 0; - } - switch (Z_TYPE_P(key)) { - case IS_LONG: - zend_hash_index_update(myht, Z_LVAL_P(key), &data, sizeof(data), NULL); - break; - case IS_STRING: - zend_hash_update(myht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL); - break; - } - zval_dtor(key); - FREE_ZVAL(key); - } - - if (Z_TYPE_PP(rval) == IS_OBJECT) { - zval *retval_ptr = NULL; - zval fname; - - INIT_PZVAL(&fname); - ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0); - call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC); - - if (retval_ptr) - zval_ptr_dtor(&retval_ptr); - } - - return *((*p)++) == '}'; - } - } - - return 0; -} - -/* }}} */ /* {{{ proto string serialize(mixed variable) Returns a string representation of variable (which can later be unserialized) */ PHP_FUNCTION(serialize) @@ -635,7 +393,7 @@ PHP_FUNCTION(serialize) PHP_FUNCTION(unserialize) { zval **buf; - php_serialize_data_t var_hash; + php_unserialize_data_t var_hash; if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(1, &buf) == FAILURE) { WRONG_PARAM_COUNT; diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c new file mode 100644 index 0000000000..fe2fdcbf00 --- /dev/null +++ b/ext/standard/var_unserializer.c @@ -0,0 +1,635 @@ +/* Generated by re2c 0.5 on Fri Nov 9 14:39:34 2001 */ +#line 1 "/home/sas/src/php4/ext/standard/var_unserializer.re" +#include "php.h" +#include "ext/standard/php_var.h" +#include "php_incomplete_class.h" + +/* {{{ reference-handling for unserializer: var_* */ +#define VAR_ENTRIES_MAX 1024 + +typedef struct { + zval *data[VAR_ENTRIES_MAX]; + int used_slots; + void *next; +} var_entries; + +static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval) +{ + var_entries *var_hash = var_hashx->first, *prev = NULL; + + while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { + prev = var_hash; + var_hash = var_hash->next; + } + + if (!var_hash) { + var_hash = emalloc(sizeof(var_entries)); + var_hash->used_slots = 0; + var_hash->next = 0; + + if (!var_hashx->first) + var_hashx->first = var_hash; + else + prev->next = var_hash; + } + + var_hash->data[var_hash->used_slots++] = *rval; +} + +void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval) +{ + int i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { + for (i = 0; i < var_hash->used_slots; i++) { + if (var_hash->data[i] == ozval) { + var_hash->data[i] = *nzval; + return; + } + } + var_hash = var_hash->next; + } +} + +static int var_access(php_unserialize_data_t *var_hashx, int id, zval ***store) +{ + var_entries *var_hash = var_hashx->first; + + while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { + var_hash = var_hash->next; + id -= VAR_ENTRIES_MAX; + } + + if (!var_hash) return !SUCCESS; + + if (id >= var_hash->used_slots) return !SUCCESS; + + *store = &var_hash->data[id]; + + return SUCCESS; +} + +void var_destroy(php_unserialize_data_t *var_hashx) +{ + void *next; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { + next = var_hash->next; + efree(var_hash); + var_hash = next; + } +} + +/* }}} */ + +#define YYFILL(n) do { } while (0) +#define YYCTYPE unsigned char +#define YYCURSOR cursor +#define YYLIMIT limit +#define YYMARKER marker + + +#line 97 + + + + +static inline int parse_iv2(const char *p, const char **q) +{ + char cursor; + int result = 0; + + while (1) { + cursor = *p; + if (cursor >= '0' && cursor <= '9') { + result = result * 10 + cursor - '0'; + } else { + break; + } + p++; + } + if (q) *q = p; + return result; +} + +static inline int parse_iv(const 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 +#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC + +static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements) +{ + while (elements-- > 0) { + zval *key, *data; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(data); + + if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(data); + FREE_ZVAL(data); + return 0; + } + + switch (Z_TYPE_P(key)) { + case IS_LONG: + zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL); + break; + 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); + } + + return 1; +} + +static inline int finish_nested_data(UNSERIALIZE_PARAMETER) +{ + if (*((*p)++) == '}') + return 1; + + zval_ptr_dtor(rval); + return 0; +} + +static inline int object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) +{ + int elements; + + elements = parse_iv2((*p) + 2, p); + + (*p) += 2; + + object_init_ex(*rval, ce); + return elements; +} + +static inline int object_common2(UNSERIALIZE_PARAMETER, int elements) +{ + zval *retval_ptr = NULL; + zval fname; + + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements)) { + return 0; + } + + INIT_PZVAL(&fname); + ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0); + call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC); + + if (retval_ptr) + zval_ptr_dtor(&retval_ptr); + + return finish_nested_data(UNSERIALIZE_PASSTHRU); + +} + +PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) +{ + const unsigned char *cursor, *limit, *marker, *start; + zval **rval_ref; + + cursor = *p; + + if (var_hash && cursor[0] != 'R') { + var_push(var_hash, rval); + } + + start = cursor; + + + +{ + YYCTYPE yych; + unsigned int yyaccept; + static unsigned char yybm[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 128, 128, 128, 128, 128, 128, 128, 128, + 128, 128, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + }; + goto yy0; +yy1: ++YYCURSOR; +yy0: + if((YYLIMIT - YYCURSOR) < 4) YYFILL(4); + yych = *YYCURSOR; + if(yych <= 'c'){ + if(yych <= 'Q'){ + if(yych <= 'M') goto yy13; + if(yych <= 'N') goto yy5; + if(yych <= 'O') goto yy12; + goto yy13; + } else { + if(yych <= '`'){ + if(yych <= 'R') goto yy3; + goto yy13; + } else { + if(yych <= 'a') goto yy10; + if(yych <= 'b') goto yy6; + goto yy13; + } + } + } else { + if(yych <= 'n'){ + if(yych <= 'd') goto yy8; + if(yych == 'i') goto yy7; + goto yy13; + } else { + if(yych <= 'r'){ + if(yych <= 'o') goto yy11; + goto yy13; + } else { + if(yych <= 's') goto yy9; + if(yych <= '\277') goto yy13; + } + } + } +yy2: YYCURSOR = YYMARKER; + switch(yyaccept){ + case 0: goto yy4; + } +yy3: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy65; +yy4: +#line 356 + { return 0; } +yy5: yych = *++YYCURSOR; + if(yych == ';') goto yy63; + goto yy4; +yy6: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy58; + goto yy4; +yy7: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy53; + goto yy4; +yy8: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy38; + goto yy4; +yy9: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy32; + goto yy4; +yy10: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy26; + goto yy4; +yy11: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy20; + goto yy4; +yy12: yyaccept = 0; + yych = *(YYMARKER = ++YYCURSOR); + if(yych == ':') goto yy14; + goto yy4; +yy13: yych = *++YYCURSOR; + goto yy4; +yy14: yych = *++YYCURSOR; + if(yybm[0+yych] & 128) goto yy15; + goto yy2; +yy15: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy16: if(yybm[0+yych] & 128) goto yy15; + if(yych != ':') goto yy2; +yy17: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +yy18: yych = *++YYCURSOR; +yy19: +#line 317 + { + int len; + int elements; + int len2; + char *class_name; + zend_class_entry *ce; + int incomplete_class = 0; + + INIT_PZVAL(*rval); + len2 = len = parse_iv(start + 2); + if (len == 0) + return 0; + + 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 (zend_hash_find(EG(class_table), class_name, len2 + 1, (void **) &ce) != SUCCESS) { + incomplete_class = 1; + ce = PHP_IC_ENTRY; + } else + efree(class_name); + + *p = YYCURSOR; + elements = object_common1(UNSERIALIZE_PASSTHRU, ce); + + if (incomplete_class) { + php_store_class_name(*rval, class_name, len2); + efree(class_name); + } + + return object_common2(UNSERIALIZE_PASSTHRU, elements); +} +yy20: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy21: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy22: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy21; + if(yych >= ';') goto yy2; +yy23: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +yy24: yych = *++YYCURSOR; +yy25: +#line 309 + { + + INIT_PZVAL(*rval); + + return object_common2(UNSERIALIZE_PASSTHRU, + object_common1(UNSERIALIZE_PASSTHRU, &zend_standard_class_def)); +} +yy26: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy27: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy28: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy27; + if(yych >= ';') goto yy2; +yy29: yych = *++YYCURSOR; + if(yych != '{') goto yy2; +yy30: yych = *++YYCURSOR; +yy31: +#line 291 + { + int elements = parse_iv(start + 2); + + *p = YYCURSOR; + + INIT_PZVAL(*rval); + Z_TYPE_PP(rval) = IS_ARRAY; + ALLOC_HASHTABLE(Z_ARRVAL_PP(rval)); + + zend_hash_init(Z_ARRVAL_PP(rval), elements + 1, NULL, ZVAL_PTR_DTOR, 0); + + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements)) { + return 0; + } + + return finish_nested_data(UNSERIALIZE_PASSTHRU); +} +yy32: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy33: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy34: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy33; + if(yych >= ';') goto yy2; +yy35: yych = *++YYCURSOR; + if(yych != '"') goto yy2; +yy36: yych = *++YYCURSOR; +yy37: +#line 271 + { + int len; + char *str; + + len = parse_iv(start + 2); + + if (len == 0) { + str = empty_string; + } else { + str = estrndup(YYCURSOR, len); + } + + YYCURSOR += len + 2; + *p = YYCURSOR; + + INIT_PZVAL(*rval); + ZVAL_STRINGL(*rval, str, len, 0); + return 1; +} +yy38: yych = *++YYCURSOR; + if(yych == '.') goto yy41; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy39: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy40: if(yych <= '/'){ + if(yych == '.') goto yy50; + goto yy2; + } else { + if(yych <= '9') goto yy39; + if(yych == ';') goto yy44; + goto yy2; + } +yy41: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy42: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy43: if(yych <= ';'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy42; + if(yych <= ':') goto yy2; + } else { + if(yych <= 'E'){ + if(yych <= 'D') goto yy2; + goto yy46; + } else { + if(yych == 'e') goto yy46; + goto yy2; + } + } +yy44: yych = *++YYCURSOR; +yy45: +#line 264 + { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_DOUBLE(*rval, atof(start + 2)); + return 1; +} +yy46: yych = *++YYCURSOR; + if(yych <= ','){ + if(yych != '+') goto yy2; + } else { + if(yych <= '-') goto yy47; + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy48; + goto yy2; + } +yy47: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy48: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy49: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy48; + if(yych == ';') goto yy44; + goto yy2; +yy50: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy51: ++YYCURSOR; + if((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; +yy52: if(yych <= ';'){ + if(yych <= '/') goto yy2; + if(yych <= '9') goto yy51; + if(yych <= ':') goto yy2; + goto yy44; + } else { + if(yych <= 'E'){ + if(yych <= 'D') goto yy2; + goto yy46; + } else { + if(yych == 'e') goto yy46; + goto yy2; + } + } +yy53: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy54: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy55: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy54; + if(yych != ';') goto yy2; +yy56: yych = *++YYCURSOR; +yy57: +#line 257 + { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_LONG(*rval, parse_iv(start + 2)); + return 1; +} +yy58: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy59: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy60: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy59; + if(yych != ';') goto yy2; +yy61: yych = *++YYCURSOR; +yy62: +#line 250 + { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_BOOL(*rval, parse_iv(start + 2)); + return 1; +} +yy63: yych = *++YYCURSOR; +yy64: +#line 243 + { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_NULL(*rval); + return 1; +} +yy65: yych = *++YYCURSOR; + if(yych <= '/') goto yy2; + if(yych >= ':') goto yy2; +yy66: ++YYCURSOR; + if(YYLIMIT == YYCURSOR) YYFILL(1); + yych = *YYCURSOR; +yy67: if(yych <= '/') goto yy2; + if(yych <= '9') goto yy66; + if(yych != ';') goto yy2; +yy68: yych = *++YYCURSOR; +yy69: +#line 224 + { + int id; + + *p = YYCURSOR; + if (!var_hash) return 0; + + id = parse_iv(start + 2) - 1; + if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) { + return 0; + } + + zval_ptr_dtor(rval); + *rval = *rval_ref; + (*rval)->refcount++; + (*rval)->is_ref = 1; + + return 1; +} +} +#line 358 + + + return 0; +} diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re new file mode 100644 index 0000000000..02c1fce66b --- /dev/null +++ b/ext/standard/var_unserializer.re @@ -0,0 +1,361 @@ +#include "php.h" +#include "ext/standard/php_var.h" +#include "php_incomplete_class.h" + +/* {{{ reference-handling for unserializer: var_* */ +#define VAR_ENTRIES_MAX 1024 + +typedef struct { + zval *data[VAR_ENTRIES_MAX]; + int used_slots; + void *next; +} var_entries; + +static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval) +{ + var_entries *var_hash = var_hashx->first, *prev = NULL; + + while (var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { + prev = var_hash; + var_hash = var_hash->next; + } + + if (!var_hash) { + var_hash = emalloc(sizeof(var_entries)); + var_hash->used_slots = 0; + var_hash->next = 0; + + if (!var_hashx->first) + var_hashx->first = var_hash; + else + prev->next = var_hash; + } + + var_hash->data[var_hash->used_slots++] = *rval; +} + +void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval) +{ + int i; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { + for (i = 0; i < var_hash->used_slots; i++) { + if (var_hash->data[i] == ozval) { + var_hash->data[i] = *nzval; + return; + } + } + var_hash = var_hash->next; + } +} + +static int var_access(php_unserialize_data_t *var_hashx, int id, zval ***store) +{ + var_entries *var_hash = var_hashx->first; + + while (id >= VAR_ENTRIES_MAX && var_hash && var_hash->used_slots == VAR_ENTRIES_MAX) { + var_hash = var_hash->next; + id -= VAR_ENTRIES_MAX; + } + + if (!var_hash) return !SUCCESS; + + if (id >= var_hash->used_slots) return !SUCCESS; + + *store = &var_hash->data[id]; + + return SUCCESS; +} + +void var_destroy(php_unserialize_data_t *var_hashx) +{ + void *next; + var_entries *var_hash = var_hashx->first; + + while (var_hash) { + next = var_hash->next; + efree(var_hash); + var_hash = next; + } +} + +/* }}} */ + +#define YYFILL(n) do { } while (0) +#define YYCTYPE unsigned char +#define YYCURSOR cursor +#define YYLIMIT limit +#define YYMARKER marker + + +/*!re2c +iv = [0-9]+; +nv = ([0-9]* "." [0-9]+|[0-9]+ "." [0-9]+); +nvexp = nv [eE] [+-]? iv; +any = [\000-\277]; +*/ + + + +static inline int parse_iv2(const char *p, const char **q) +{ + char cursor; + int result = 0; + + while (1) { + cursor = *p; + if (cursor >= '0' && cursor <= '9') { + result = result * 10 + cursor - '0'; + } else { + break; + } + p++; + } + if (q) *q = p; + return result; +} + +static inline int parse_iv(const 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 +#define UNSERIALIZE_PASSTHRU rval, p, max, var_hash TSRMLS_CC + +static inline int process_nested_data(UNSERIALIZE_PARAMETER, HashTable *ht, int elements) +{ + while (elements-- > 0) { + zval *key, *data; + + ALLOC_INIT_ZVAL(key); + + if (!php_var_unserialize(&key, p, max, NULL TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + return 0; + } + + ALLOC_INIT_ZVAL(data); + + if (!php_var_unserialize(&data, p, max, var_hash TSRMLS_CC)) { + zval_dtor(key); + FREE_ZVAL(key); + zval_dtor(data); + FREE_ZVAL(data); + return 0; + } + + switch (Z_TYPE_P(key)) { + case IS_LONG: + zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL); + break; + 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); + } + + return 1; +} + +static inline int finish_nested_data(UNSERIALIZE_PARAMETER) +{ + if (*((*p)++) == '}') + return 1; + + zval_ptr_dtor(rval); + return 0; +} + +static inline int object_common1(UNSERIALIZE_PARAMETER, zend_class_entry *ce) +{ + int elements; + + elements = parse_iv2((*p) + 2, p); + + (*p) += 2; + + object_init_ex(*rval, ce); + return elements; +} + +static inline int object_common2(UNSERIALIZE_PARAMETER, int elements) +{ + zval *retval_ptr = NULL; + zval fname; + + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_OBJPROP_PP(rval), elements)) { + return 0; + } + + INIT_PZVAL(&fname); + ZVAL_STRINGL(&fname, "__wakeup", sizeof("__wakeup") - 1, 0); + call_user_function_ex(CG(function_table), rval, &fname, &retval_ptr, 0, 0, 1, NULL TSRMLS_CC); + + if (retval_ptr) + zval_ptr_dtor(&retval_ptr); + + return finish_nested_data(UNSERIALIZE_PASSTHRU); + +} + +PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER) +{ + const unsigned char *cursor, *limit, *marker, *start; + zval **rval_ref; + + cursor = *p; + + if (var_hash && cursor[0] != 'R') { + var_push(var_hash, rval); + } + + start = cursor; + + + +/*!re2c +"R:" iv ";" { + int id; + + *p = YYCURSOR; + if (!var_hash) return 0; + + id = parse_iv(start + 2) - 1; + if (id == -1 || var_access(var_hash, id, &rval_ref) != SUCCESS) { + return 0; + } + + zval_ptr_dtor(rval); + *rval = *rval_ref; + (*rval)->refcount++; + (*rval)->is_ref = 1; + + return 1; +} + +"N;" { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_NULL(*rval); + return 1; +} + +"b:" iv ";" { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_BOOL(*rval, parse_iv(start + 2)); + return 1; +} + +"i:" iv ";" { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_LONG(*rval, parse_iv(start + 2)); + return 1; +} + +"d:" (iv | nv | nvexp) ";" { + *p = YYCURSOR; + INIT_PZVAL(*rval); + ZVAL_DOUBLE(*rval, atof(start + 2)); + return 1; +} + +"s:" iv ":" ["] { + int len; + char *str; + + len = parse_iv(start + 2); + + if (len == 0) { + str = empty_string; + } else { + str = estrndup(YYCURSOR, len); + } + + YYCURSOR += len + 2; + *p = YYCURSOR; + + INIT_PZVAL(*rval); + ZVAL_STRINGL(*rval, str, len, 0); + return 1; +} + +"a:" iv ":" "{" { + int elements = parse_iv(start + 2); + + *p = YYCURSOR; + + INIT_PZVAL(*rval); + Z_TYPE_PP(rval) = IS_ARRAY; + ALLOC_HASHTABLE(Z_ARRVAL_PP(rval)); + + zend_hash_init(Z_ARRVAL_PP(rval), elements + 1, NULL, ZVAL_PTR_DTOR, 0); + + if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements)) { + return 0; + } + + return finish_nested_data(UNSERIALIZE_PASSTHRU); +} + +"o:" iv ":" ["] { + + INIT_PZVAL(*rval); + + return object_common2(UNSERIALIZE_PASSTHRU, + object_common1(UNSERIALIZE_PASSTHRU, &zend_standard_class_def)); +} + +"O:" iv ":" ["] { + int len; + int elements; + int len2; + char *class_name; + zend_class_entry *ce; + int incomplete_class = 0; + + INIT_PZVAL(*rval); + len2 = len = parse_iv(start + 2); + if (len == 0) + return 0; + + 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 (zend_hash_find(EG(class_table), class_name, len2 + 1, (void **) &ce) != SUCCESS) { + incomplete_class = 1; + ce = PHP_IC_ENTRY; + } else + efree(class_name); + + *p = YYCURSOR; + elements = object_common1(UNSERIALIZE_PASSTHRU, ce); + + if (incomplete_class) { + php_store_class_name(*rval, class_name, len2); + efree(class_name); + } + + return object_common2(UNSERIALIZE_PASSTHRU, elements); +} + +any { return 0; } + +*/ + + return 0; +} |