summaryrefslogtreecommitdiff
path: root/ext/session
diff options
context:
space:
mode:
authorXinchen Hui <laruence@gmail.com>2016-04-15 21:08:51 -0700
committerXinchen Hui <laruence@gmail.com>2016-04-15 21:08:51 -0700
commit05d53dee7d70a94c0cef57ae2dae735f98a3d833 (patch)
tree4fca82e523e3aacf831aa0de5a3a796d2daef918 /ext/session
parentedb569b439097093838cf548201dc98fd78b7c71 (diff)
downloadphp-git-05d53dee7d70a94c0cef57ae2dae735f98a3d833.tar.gz
Fixed bug #71972 (Cyclic references causing session_start(): Failed to decode session object)
Diffstat (limited to 'ext/session')
-rw-r--r--ext/session/session.c62
-rw-r--r--ext/session/tests/bug71972.phpt28
2 files changed, 69 insertions, 21 deletions
diff --git a/ext/session/session.c b/ext/session/session.c
index e745b96867..5b7841de5c 100644
--- a/ext/session/session.c
+++ b/ext/session/session.c
@@ -498,7 +498,6 @@ static void php_session_gc(void) /* {{{ */
}
} /* }}} */
-
static void php_session_initialize(void) /* {{{ */
{
zend_string *val = NULL;
@@ -613,6 +612,22 @@ static void php_session_save_current_state(int write) /* {{{ */
}
/* }}} */
+static void php_session_normalize_vars() /* {{{ */
+{
+ PS_ENCODE_VARS;
+
+ IF_SESSION_VARS() {
+ PS_ENCODE_LOOP(
+ if (Z_TYPE_P(struc) == IS_PTR) {
+ zval *zv = (zval *)Z_PTR_P(struc);
+ ZVAL_COPY_VALUE(struc, zv);
+ ZVAL_UNDEF(zv);
+ }
+ );
+ }
+}
+/* }}} */
+
/* *************************
* INI Settings/Handlers *
************************* */
@@ -944,7 +959,6 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
{
const char *p;
const char *endptr = val + vallen;
- zval current;
int has_value;
int namelen;
zend_string *name;
@@ -967,28 +981,32 @@ PS_SERIALIZER_DECODE_FUNC(php_binary) /* {{{ */
p += namelen + 1;
if ((tmp = zend_hash_find(&EG(symbol_table), name))) {
- if ((Z_TYPE_P(tmp) == IS_ARRAY && Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) {
+ if ((Z_TYPE_P(tmp) == IS_ARRAY &&
+ Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) {
zend_string_release(name);
continue;
}
}
if (has_value) {
- ZVAL_UNDEF(&current);
- if (php_var_unserialize(&current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash)) {
- zval *zv = php_set_session_var(name, &current, &var_hash );
- var_replace(&var_hash, &current, zv);
+ zval *current, rv;
+ current = var_tmp_var(&var_hash);
+ if (php_var_unserialize(current, (const unsigned char **) &p, (const unsigned char *) endptr, &var_hash)) {
+ ZVAL_PTR(&rv, current);
+ php_set_session_var(name, &rv, &var_hash );
} else {
- zval_ptr_dtor(&current);
zend_string_release(name);
+ php_session_normalize_vars();
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return FAILURE;
}
+ } else {
+ PS_ADD_VARL(name);
}
- PS_ADD_VARL(name);
zend_string_release(name);
}
+ php_session_normalize_vars();
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
return SUCCESS;
@@ -1033,10 +1051,9 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
{
const char *p, *q;
const char *endptr = val + vallen;
- zval current;
- int has_value;
ptrdiff_t namelen;
zend_string *name;
+ int has_value, retval = SUCCESS;
php_unserialize_data_t var_hash;
PHP_VAR_UNSERIALIZE_INIT(var_hash);
@@ -1061,34 +1078,37 @@ PS_SERIALIZER_DECODE_FUNC(php) /* {{{ */
q++;
if ((tmp = zend_hash_find(&EG(symbol_table), name))) {
- if ((Z_TYPE_P(tmp) == IS_ARRAY && Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) {
+ if ((Z_TYPE_P(tmp) == IS_ARRAY &&
+ Z_ARRVAL_P(tmp) == &EG(symbol_table)) || tmp == &PS(http_session_vars)) {
goto skip;
}
}
if (has_value) {
- ZVAL_UNDEF(&current);
- if (php_var_unserialize(&current, (const unsigned char **) &q, (const unsigned char *) endptr, &var_hash)) {
- zval *zv = php_set_session_var(name, &current, &var_hash);
- var_replace(&var_hash, &current, zv);
+ zval *current, rv;
+ current = var_tmp_var(&var_hash);
+ if (php_var_unserialize(current, (const unsigned char **)&q, (const unsigned char *)endptr, &var_hash)) {
+ ZVAL_PTR(&rv, current);
+ php_set_session_var(name, &rv, &var_hash);
} else {
- zval_ptr_dtor(&current);
- PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
zend_string_release(name);
- return FAILURE;
+ retval = FAILURE;
+ goto break_outer_loop;
}
+ } else {
+ PS_ADD_VARL(name);
}
- PS_ADD_VARL(name);
skip:
zend_string_release(name);
p = q;
}
break_outer_loop:
+ php_session_normalize_vars();
PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
- return SUCCESS;
+ return retval;
}
/* }}} */
diff --git a/ext/session/tests/bug71972.phpt b/ext/session/tests/bug71972.phpt
new file mode 100644
index 0000000000..e4c5c6b6d3
--- /dev/null
+++ b/ext/session/tests/bug71972.phpt
@@ -0,0 +1,28 @@
+--TEST--
+Bug #71972 (Cyclic references causing session_start(): Failed to decode session object)
+--SKIPIF--
+<?php include('skipif.inc'); ?>
+--INI--
+session.save_handler=files
+--FILE--
+<?php
+ob_start();
+session_start();
+
+$_SESSION['boogie'] = 1;
+
+$_SESSION['obj1'] = new stdClass();
+for ( $x=2; $x < 20; $x++) {
+ cyclic_ref($x);
+}
+
+function cyclic_ref($num) {
+ $_SESSION['obj'.$num] = new stdClass();
+ $_SESSION['obj'.$num]->test = new stdClass();//NOTE: No bug if try commenting out this too.
+ $_SESSION['obj'.$num]->obj1 = $_SESSION['obj1'];
+}
+
+var_dump(session_decode(session_encode()) == $_SESSION);
+?>
+--EXPECT--
+bool(true)