diff options
| -rw-r--r-- | ext/session/php_session.h | 2 | ||||
| -rw-r--r-- | ext/session/session.c | 55 | ||||
| -rw-r--r-- | ext/session/tests/006.phpt | 62 | ||||
| -rw-r--r-- | ext/standard/php_var.h | 19 | ||||
| -rw-r--r-- | ext/wddx/wddx.c | 2 |
5 files changed, 113 insertions, 27 deletions
diff --git a/ext/session/php_session.h b/ext/session/php_session.h index 0f71e91b7b..97623915b5 100644 --- a/ext/session/php_session.h +++ b/ext/session/php_session.h @@ -155,7 +155,7 @@ void session_adapt_url(const char *, size_t, char **, size_t *); #define session_adapt_url(a,b,c,d) #endif -void php_set_session_var(char *name, size_t namelen, zval *state_val PSLS_DC); +void php_set_session_var(char *name, size_t namelen, zval *state_val,HashTable *var_hash PSLS_DC); int php_get_session_var(char *name, size_t namelen, zval ***state_var PLS_DC PSLS_DC ELS_DC); int php_session_register_module(ps_module *); diff --git a/ext/session/session.c b/ext/session/session.c index 4f741f428a..d373b5a757 100644 --- a/ext/session/session.c +++ b/ext/session/session.c @@ -232,36 +232,39 @@ typedef struct { #define MAX_STR 512 -void php_set_session_var(char *name, size_t namelen, zval *state_val PSLS_DC) +void php_set_session_var(char *name, size_t namelen, zval *state_val,HashTable *var_hash PSLS_DC) { - zval *state_val_copy; PLS_FETCH(); ELS_FETCH(); - ALLOC_ZVAL(state_val_copy); - *state_val_copy = *state_val; - zval_copy_ctor(state_val_copy); - state_val_copy->refcount = 0; - if (PG(register_globals)) { zval **old_symbol; - if(zend_hash_find(&EG(symbol_table),name,namelen+1,(void *)&old_symbol) == SUCCESS) { + if (zend_hash_find(&EG(symbol_table),name,namelen+1,(void *)&old_symbol) == SUCCESS) { /* There where old one, we need to replace it accurately. hash_update in zend_set_hash_symbol is not good, because it will leave referenced variables (such as local instances of a global variable) dangling. + + BTW: if you use register_globals references between + session-vars won't work because of this very reason! */ + - REPLACE_ZVAL_VALUE(old_symbol,state_val_copy,0); - FREE_ZVAL(state_val_copy); + REPLACE_ZVAL_VALUE(old_symbol,state_val,1); + + /* the following line will muck with the reference-table used for + * unserialisation + */ + + PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash,state_val,*old_symbol); zend_set_hash_symbol(*old_symbol, name, namelen, 1, 1, Z_ARRVAL_P(PS(http_session_vars))); } else { - zend_set_hash_symbol(state_val_copy, name, namelen, 1, 2, Z_ARRVAL_P(PS(http_session_vars)), &EG(symbol_table)); + zend_set_hash_symbol(state_val, name, namelen, 1, 2, Z_ARRVAL_P(PS(http_session_vars)), &EG(symbol_table)); } } else { - zend_set_hash_symbol(state_val_copy, name, namelen, 0, 1, Z_ARRVAL_P(PS(http_session_vars))); + zend_set_hash_symbol(state_val, name, namelen, 0, 1, Z_ARRVAL_P(PS(http_session_vars))); } } @@ -329,7 +332,6 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) PHP_VAR_UNSERIALIZE_INIT(var_hash); - MAKE_STD_ZVAL(current); for (p = val; p < endptr; ) { namelen = *p & (~PS_BIN_UNDEF); has_value = *p & PS_BIN_UNDEF ? 0 : 1; @@ -339,15 +341,16 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) p += namelen + 1; if (has_value) { + MAKE_STD_ZVAL(current); if (php_var_unserialize(¤t, &p, endptr, &var_hash)) { - php_set_session_var(name, namelen, current PSLS_CC); - zval_dtor(current); + php_set_session_var(name, namelen, current, &var_hash PSLS_CC); } + zval_ptr_dtor(¤t); } PS_ADD_VARL(name, namelen); efree(name); } - FREE_ZVAL(current); + PHP_VAR_UNSERIALIZE_DESTROY(var_hash); return SUCCESS; @@ -405,7 +408,6 @@ PS_SERIALIZER_DECODE_FUNC(php) PHP_VAR_UNSERIALIZE_INIT(var_hash); - MAKE_STD_ZVAL(current); for (p = q = val; (p < endptr) && (q = memchr(p, PS_DELIMITER, endptr - p)); p = q) { if (p[0] == PS_UNDEF_MARKER) { p++; @@ -419,17 +421,18 @@ PS_SERIALIZER_DECODE_FUNC(php) q++; if (has_value) { + MAKE_STD_ZVAL(current); if (php_var_unserialize(¤t, &q, endptr, &var_hash)) { - php_set_session_var(name, namelen, current PSLS_CC); - zval_dtor(current); + php_set_session_var(name, namelen, current, &var_hash PSLS_CC); } + zval_ptr_dtor(¤t); } PS_ADD_VARL(name, namelen); efree(name); } - FREE_ZVAL(current); PHP_VAR_UNSERIALIZE_DESTROY(var_hash); + return SUCCESS; } @@ -543,18 +546,20 @@ static void php_session_save_current_state(PSLS_D) int vallen; int ret = FAILURE; char *variable; + ulong variable_len; ulong num_key; + HashPosition pos; PLS_FETCH(); if (!PG(register_globals)) { if (!PS(http_session_vars)) { return; } - - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(PS(http_session_vars))); - zend_hash_get_current_key(Z_ARRVAL_P(PS(http_session_vars)), &variable, &num_key, 1) == HASH_KEY_IS_STRING; - zend_hash_move_forward(Z_ARRVAL_P(PS(http_session_vars)))) { - PS_ADD_VAR(variable); + + for (zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(PS(http_session_vars)), &pos); + zend_hash_get_current_key_ex(Z_ARRVAL_P(PS(http_session_vars)), &variable, &variable_len, &num_key, 0, &pos) == HASH_KEY_IS_STRING; + zend_hash_move_forward_ex(Z_ARRVAL_P(PS(http_session_vars)),&pos)) { + PS_ADD_VARL(variable,variable_len-1); } } diff --git a/ext/session/tests/006.phpt b/ext/session/tests/006.phpt new file mode 100644 index 0000000000..91f1cb949d --- /dev/null +++ b/ext/session/tests/006.phpt @@ -0,0 +1,62 @@ +--TEST-- +References between variables in sessions +--FILE-- +<?php +ob_start(); +session_id("test"); +session_start(); + +class a { + var $test = "hallo"; +} + +class b { + var $a; + function b(&$a) { + $this->a = &$a; + } +} + +$a = new a(); +$b = new b($a); + +echo "original values:\n"; +var_dump($a,$b); + +session_register("a"); +session_register("b"); +session_write_close(); + +session_unregister("a"); +session_unregister("b"); + +session_start(); + +echo "values after session:\n"; +var_dump($a,$b); +?> +--EXPECT-- +original values: +object(a)(1) { + ["test"]=> + string(5) "hallo" +} +object(b)(1) { + ["a"]=> + &object(a)(1) { + ["test"]=> + string(5) "hallo" + } +} +values after session: +object(a)(1) { + ["test"]=> + string(5) "hallo" +} +object(b)(1) { + ["a"]=> + &object(a)(1) { + ["test"]=> + string(5) "hallo" + } +} diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h index ddaaf0fa12..7e2391adc3 100644 --- a/ext/standard/php_var.h +++ b/ext/standard/php_var.h @@ -43,6 +43,25 @@ int php_var_unserialize(pval **rval, const char **p, const char *max, php_serial #define PHP_VAR_UNSERIALIZE_DESTROY(var_hash) \ zend_hash_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; \ + ulong 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); \ + } \ +} + PHPAPI zend_class_entry *php_create_empty_class(char *class_name,int len); #endif /* PHP_VAR_H */ diff --git a/ext/wddx/wddx.c b/ext/wddx/wddx.c index 8c894cfa83..365f6cecb6 100644 --- a/ext/wddx/wddx.c +++ b/ext/wddx/wddx.c @@ -271,7 +271,7 @@ PS_SERIALIZER_DECODE_FUNC(wddx) key = tmp; /* fallthru */ case HASH_KEY_IS_STRING: - php_set_session_var(key, key_length-1, *ent PSLS_CC); + php_set_session_var(key, key_length-1, *ent, NULL PSLS_CC); PS_ADD_VAR(key); } } |
