summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Jones <sixd@php.net>2013-08-19 17:55:25 -0700
committerChristopher Jones <sixd@php.net>2013-08-19 17:55:25 -0700
commitdc384a571d4418d274f9ba9b270696950318daaa (patch)
tree01ae766f3c45ff0a1ff2e9bb8d5623ee546b86d8
parent71c24f4c2e65d7d7fc3679cc14e846cdea83c82e (diff)
parentc60067c09a32af325d6cd70e4cfa6db3c78a8621 (diff)
downloadphp-git-dc384a571d4418d274f9ba9b270696950318daaa.tar.gz
Merge branch 'PHP-5.4' of https://git.php.net/repository/php-src into PHP-5.4
* 'PHP-5.4' of https://git.php.net/repository/php-src: Update NEWS fix bug #65481 (shutdown segfault due to serialize) Track created curl_slist structs by option so they can be updated in situ. Fixed bug #64503 (Compilation fails with error: conflicting types for 'zendparse').
-rw-r--r--NEWS6
-rw-r--r--Zend/zend_language_parser.y12
-rw-r--r--ext/curl/interface.c14
-rw-r--r--ext/curl/php_curl.h2
-rw-r--r--ext/curl/tests/bug65458.phpt25
-rw-r--r--ext/standard/php_var.h1
-rw-r--r--ext/standard/tests/serialize/bug65481.phpt40
-rw-r--r--ext/standard/var_unserializer.c117
-rw-r--r--ext/standard/var_unserializer.re53
9 files changed, 200 insertions, 70 deletions
diff --git a/NEWS b/NEWS
index ff79a29bd7..8894bb4112 100644
--- a/NEWS
+++ b/NEWS
@@ -3,8 +3,9 @@ PHP NEWS
?? ??? 2013, PHP 5.4.19
- Core:
+ . Fixed bug #65481 (shutdown segfault due to serialize) (Mike)
. Fixed bug #65470 (Segmentation fault in zend_error() with
- --enable-dtrace). (Chris Jones)
+ --enable-dtrace). (Chris Jones, Kris Van Hees)
. Fixed bug #65372 (Segfault in gc_zval_possible_root when return reference
fails). (Laruence)
. Fixed bug #65304 (Use of max int in array_sum). (Laruence)
@@ -19,6 +20,9 @@ PHP NEWS
. Fixed bug #61268 (--enable-dtrace leads make to clobber
Zend/zend_dtrace.d) (Chris Jones)
+- cURL:
+ . Fixed bug #65458 (curl memory leak). (Adam)
+
- Openssl:
. Fixed bug #64802 (openssl_x509_parse fails to parse subject properly in
some cases). (Mark Jones)
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 1f5d73296f..bf48bb73d9 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -41,17 +41,19 @@ static YYSIZE_T zend_yytnamerr(char*, const char*);
#define YYERROR_VERBOSE
#define YYSTYPE znode
-#ifdef ZTS
-# define YYPARSE_PARAM tsrm_ls
-# define YYLEX_PARAM tsrm_ls
-#endif
-
%}
%pure_parser
%expect 3
+%code requires {
+#ifdef ZTS
+# define YYPARSE_PARAM tsrm_ls
+# define YYLEX_PARAM tsrm_ls
+#endif
+}
+
%token END 0 "end of file"
%left T_INCLUDE T_INCLUDE_ONCE T_EVAL T_REQUIRE T_REQUIRE_ONCE
%token T_INCLUDE "include (T_INCLUDE)"
diff --git a/ext/curl/interface.c b/ext/curl/interface.c
index 531f15ba15..f79d0d54c2 100644
--- a/ext/curl/interface.c
+++ b/ext/curl/interface.c
@@ -1373,9 +1373,9 @@ static void curl_free_post(void **post)
/* {{{ curl_free_slist
*/
-static void curl_free_slist(void **slist)
+static void curl_free_slist(void *slist)
{
- curl_slist_free_all((struct curl_slist *) *slist);
+ curl_slist_free_all(*((struct curl_slist **) slist));
}
/* }}} */
@@ -1443,8 +1443,10 @@ static void alloc_curl_handle(php_curl **ch)
(*ch)->handlers->read->stream = NULL;
zend_llist_init(&(*ch)->to_free->str, sizeof(char *), (llist_dtor_func_t) curl_free_string, 0);
- zend_llist_init(&(*ch)->to_free->slist, sizeof(struct curl_slist), (llist_dtor_func_t) curl_free_slist, 0);
zend_llist_init(&(*ch)->to_free->post, sizeof(struct HttpPost), (llist_dtor_func_t) curl_free_post, 0);
+
+ (*ch)->to_free->slist = emalloc(sizeof(HashTable));
+ zend_hash_init((*ch)->to_free->slist, 4, NULL, curl_free_slist, 0);
}
/* }}} */
@@ -1675,6 +1677,7 @@ PHP_FUNCTION(curl_copy_handle)
curl_easy_setopt(dupch->cp, CURLOPT_WRITEHEADER, (void *) dupch);
curl_easy_setopt(dupch->cp, CURLOPT_PROGRESSDATA, (void *) dupch);
+ efree(dupch->to_free->slist);
efree(dupch->to_free);
dupch->to_free = ch->to_free;
@@ -2184,7 +2187,7 @@ string_copy:
return 1;
}
}
- zend_llist_add_element(&ch->to_free->slist, &slist);
+ zend_hash_index_update(ch->to_free->slist, (ulong) option, &slist, sizeof(struct curl_slist *), NULL);
error = curl_easy_setopt(ch->cp, option, slist);
@@ -2680,8 +2683,9 @@ static void _php_curl_close_ex(php_curl *ch TSRMLS_DC)
/* cURL destructors should be invoked only by last curl handle */
if (Z_REFCOUNT_P(ch->clone) <= 1) {
zend_llist_clean(&ch->to_free->str);
- zend_llist_clean(&ch->to_free->slist);
zend_llist_clean(&ch->to_free->post);
+ zend_hash_destroy(ch->to_free->slist);
+ efree(ch->to_free->slist);
efree(ch->to_free);
FREE_ZVAL(ch->clone);
} else {
diff --git a/ext/curl/php_curl.h b/ext/curl/php_curl.h
index 945f0a4307..911d87a6b4 100644
--- a/ext/curl/php_curl.h
+++ b/ext/curl/php_curl.h
@@ -126,7 +126,7 @@ struct _php_curl_send_headers {
struct _php_curl_free {
zend_llist str;
zend_llist post;
- zend_llist slist;
+ HashTable *slist;
};
typedef struct {
diff --git a/ext/curl/tests/bug65458.phpt b/ext/curl/tests/bug65458.phpt
new file mode 100644
index 0000000000..99288f24be
--- /dev/null
+++ b/ext/curl/tests/bug65458.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #65458 (curl memory leak)
+--SKIPIF--
+<?php
+if (!extension_loaded('curl')) exit("skip curl extension not loaded");
+?>
+--FILE--
+<?php
+$ch = curl_init();
+$init = memory_get_usage();
+for ($i = 0; $i < 10000; $i++) {
+ curl_setopt($ch, CURLOPT_HTTPHEADER, [ "SOAPAction: getItems" ]);
+}
+
+$preclose = memory_get_usage();
+curl_close($ch);
+
+// This is a slightly tricky heuristic, but basically, we want to ensure
+// $preclose - $init has a delta in the order of bytes, not megabytes. Given
+// the number of iterations in the loop, if we're wasting memory here, we
+// should have megs and megs of extra allocations.
+var_dump(($preclose - $init) < 10000);
+?>
+--EXPECT--
+bool(true)
diff --git a/ext/standard/php_var.h b/ext/standard/php_var.h
index 35343b3d5d..afc5f178e4 100644
--- a/ext/standard/php_var.h
+++ b/ext/standard/php_var.h
@@ -115,6 +115,7 @@ do { \
PHPAPI void var_replace(php_unserialize_data_t *var_hash, zval *ozval, zval **nzval);
PHPAPI void var_push_dtor(php_unserialize_data_t *var_hash, zval **val);
+PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval);
PHPAPI void var_destroy(php_unserialize_data_t *var_hash);
#define PHP_VAR_UNSERIALIZE_ZVAL_CHANGED(var_hash, ozval, nzval) \
diff --git a/ext/standard/tests/serialize/bug65481.phpt b/ext/standard/tests/serialize/bug65481.phpt
new file mode 100644
index 0000000000..65634f63ba
--- /dev/null
+++ b/ext/standard/tests/serialize/bug65481.phpt
@@ -0,0 +1,40 @@
+--TEST--
+Bug #65481 (shutdown segfault due to serialize)
+--FILE--
+<?php
+echo "Test\n";
+
+class A {
+ public $e = array();
+}
+
+class Token implements \Serializable {
+ public function serialize()
+ {
+ $c = new A;
+
+ for ($i = 0; $i < 4; $i++)
+ {
+ $e = new A;
+ $c->e[] = $e;
+ $e->e = $c->e;
+ }
+
+ return serialize(array(serialize($c)));
+ }
+
+ public function unserialize($str)
+ {
+ $r = unserialize($str);
+ $r = unserialize($r[0]);
+ }
+}
+
+$token = new Token;
+$token = serialize($token);
+
+?>
+Done
+--EXPECT--
+Test
+Done
diff --git a/ext/standard/var_unserializer.c b/ext/standard/var_unserializer.c
index d8bae08d2a..8a35e0a5af 100644
--- a/ext/standard/var_unserializer.c
+++ b/ext/standard/var_unserializer.c
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 on Sat Mar 9 22:33:09 2013 */
+/* Generated by re2c 0.13.5 on Mon Jul 29 17:57:26 2013 */
#line 1 "ext/standard/var_unserializer.re"
/*
+----------------------------------------------------------------------+
@@ -26,6 +26,7 @@
/* {{{ reference-handling for unserializer: var_* */
#define VAR_ENTRIES_MAX 1024
+#define VAR_ENTRIES_DBG 0
typedef struct {
zval *data[VAR_ENTRIES_MAX];
@@ -36,7 +37,7 @@ typedef struct {
static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
{
var_entries *var_hash = (*var_hashx)->last;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
#endif
@@ -60,7 +61,7 @@ static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
{
var_entries *var_hash = (*var_hashx)->last_dtor;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_push_dtor(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
#endif
@@ -82,11 +83,35 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
var_hash->data[var_hash->used_slots++] = *rval;
}
+PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval)
+{
+ var_entries *var_hash = (*var_hashx)->last_dtor;
+#if VAR_ENTRIES_DBG
+ fprintf(stderr, "var_push_dtor_no_addref(%ld): %d (%d)\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval));
+#endif
+
+ if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
+ var_hash = emalloc(sizeof(var_entries));
+ var_hash->used_slots = 0;
+ var_hash->next = 0;
+
+ if (!(*var_hashx)->first_dtor) {
+ (*var_hashx)->first_dtor = var_hash;
+ } else {
+ ((var_entries *) (*var_hashx)->last_dtor)->next = var_hash;
+ }
+
+ (*var_hashx)->last_dtor = var_hash;
+ }
+
+ var_hash->data[var_hash->used_slots++] = *rval;
+}
+
PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval)
{
long i;
var_entries *var_hash = (*var_hashx)->first;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(nzval));
#endif
@@ -104,7 +129,7 @@ PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **n
static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store)
{
var_entries *var_hash = (*var_hashx)->first;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id);
#endif
@@ -127,7 +152,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
void *next;
long i;
var_entries *var_hash = (*var_hashx)->first;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L);
#endif
@@ -201,7 +226,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 234 "ext/standard/var_unserializer.re"
@@ -432,7 +457,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
-#line 436 "ext/standard/var_unserializer.c"
+#line 461 "ext/standard/var_unserializer.c"
{
YYCTYPE yych;
static const unsigned char yybm[] = {
@@ -492,9 +517,9 @@ yy2:
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy95;
yy3:
-#line 785 "ext/standard/var_unserializer.re"
+#line 812 "ext/standard/var_unserializer.re"
{ return 0; }
-#line 498 "ext/standard/var_unserializer.c"
+#line 523 "ext/standard/var_unserializer.c"
yy4:
yych = *(YYMARKER = ++YYCURSOR);
if (yych == ':') goto yy89;
@@ -537,13 +562,13 @@ yy13:
goto yy3;
yy14:
++YYCURSOR;
-#line 779 "ext/standard/var_unserializer.re"
+#line 806 "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 572 "ext/standard/var_unserializer.c"
yy16:
yych = *++YYCURSOR;
goto yy3;
@@ -573,7 +598,7 @@ yy20:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 635 "ext/standard/var_unserializer.re"
+#line 660 "ext/standard/var_unserializer.re"
{
size_t len, len2, len3, maxlen;
long elements;
@@ -625,9 +650,9 @@ yy20:
do {
/* Try to find class directly */
- BG(serialize_lock) = 1;
+ BG(serialize_lock)++;
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (EG(exception)) {
efree(class_name);
return 0;
@@ -635,7 +660,7 @@ yy20:
ce = *pce;
break;
}
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (EG(exception)) {
efree(class_name);
@@ -655,9 +680,9 @@ yy20:
args[0] = &arg_func_name;
MAKE_STD_ZVAL(arg_func_name);
ZVAL_STRING(arg_func_name, class_name, 1);
- BG(serialize_lock) = 1;
+ BG(serialize_lock)++;
if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (EG(exception)) {
efree(class_name);
zval_ptr_dtor(&user_func);
@@ -671,7 +696,7 @@ yy20:
zval_ptr_dtor(&arg_func_name);
break;
}
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
@@ -699,7 +724,9 @@ yy20:
*p = YYCURSOR;
if (custom_object) {
- int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
+ int ret;
+
+ ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
if (ret && incomplete_class) {
php_store_class_name(*rval, class_name, len2);
@@ -717,7 +744,7 @@ yy20:
return object_common2(UNSERIALIZE_PASSTHRU, elements);
}
-#line 721 "ext/standard/var_unserializer.c"
+#line 748 "ext/standard/var_unserializer.c"
yy25:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -742,7 +769,7 @@ yy27:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 627 "ext/standard/var_unserializer.re"
+#line 652 "ext/standard/var_unserializer.re"
{
INIT_PZVAL(*rval);
@@ -750,7 +777,7 @@ yy27:
return object_common2(UNSERIALIZE_PASSTHRU,
object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
}
-#line 754 "ext/standard/var_unserializer.c"
+#line 781 "ext/standard/var_unserializer.c"
yy32:
yych = *++YYCURSOR;
if (yych == '+') goto yy33;
@@ -771,7 +798,7 @@ yy34:
yych = *++YYCURSOR;
if (yych != '{') goto yy18;
++YYCURSOR;
-#line 607 "ext/standard/var_unserializer.re"
+#line 632 "ext/standard/var_unserializer.re"
{
long elements = parse_iv(start + 2);
/* use iv() not uiv() in order to check data range */
@@ -791,7 +818,7 @@ yy34:
return finish_nested_data(UNSERIALIZE_PASSTHRU);
}
-#line 795 "ext/standard/var_unserializer.c"
+#line 822 "ext/standard/var_unserializer.c"
yy39:
yych = *++YYCURSOR;
if (yych == '+') goto yy40;
@@ -812,7 +839,7 @@ yy41:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 578 "ext/standard/var_unserializer.re"
+#line 603 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -841,7 +868,7 @@ yy41:
ZVAL_STRINGL(*rval, str, len, 0);
return 1;
}
-#line 845 "ext/standard/var_unserializer.c"
+#line 872 "ext/standard/var_unserializer.c"
yy46:
yych = *++YYCURSOR;
if (yych == '+') goto yy47;
@@ -862,7 +889,7 @@ yy48:
yych = *++YYCURSOR;
if (yych != '"') goto yy18;
++YYCURSOR;
-#line 550 "ext/standard/var_unserializer.re"
+#line 575 "ext/standard/var_unserializer.re"
{
size_t len, maxlen;
char *str;
@@ -890,7 +917,7 @@ yy48:
ZVAL_STRINGL(*rval, str, len, 1);
return 1;
}
-#line 894 "ext/standard/var_unserializer.c"
+#line 921 "ext/standard/var_unserializer.c"
yy53:
yych = *++YYCURSOR;
if (yych <= '/') {
@@ -978,7 +1005,7 @@ yy61:
}
yy63:
++YYCURSOR;
-#line 540 "ext/standard/var_unserializer.re"
+#line 565 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
use_double:
@@ -988,7 +1015,7 @@ use_double:
ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
return 1;
}
-#line 992 "ext/standard/var_unserializer.c"
+#line 1019 "ext/standard/var_unserializer.c"
yy65:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1047,7 +1074,7 @@ yy73:
yych = *++YYCURSOR;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 525 "ext/standard/var_unserializer.re"
+#line 550 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
@@ -1062,7 +1089,7 @@ yy73:
return 1;
}
-#line 1066 "ext/standard/var_unserializer.c"
+#line 1093 "ext/standard/var_unserializer.c"
yy76:
yych = *++YYCURSOR;
if (yych == 'N') goto yy73;
@@ -1089,7 +1116,7 @@ yy79:
if (yych <= '9') goto yy79;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 498 "ext/standard/var_unserializer.re"
+#line 523 "ext/standard/var_unserializer.re"
{
#if SIZEOF_LONG == 4
int digits = YYCURSOR - start - 3;
@@ -1116,7 +1143,7 @@ yy79:
ZVAL_LONG(*rval, parse_iv(start + 2));
return 1;
}
-#line 1120 "ext/standard/var_unserializer.c"
+#line 1147 "ext/standard/var_unserializer.c"
yy83:
yych = *++YYCURSOR;
if (yych <= '/') goto yy18;
@@ -1124,24 +1151,24 @@ yy83:
yych = *++YYCURSOR;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 491 "ext/standard/var_unserializer.re"
+#line 516 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
ZVAL_BOOL(*rval, parse_iv(start + 2));
return 1;
}
-#line 1135 "ext/standard/var_unserializer.c"
+#line 1162 "ext/standard/var_unserializer.c"
yy87:
++YYCURSOR;
-#line 484 "ext/standard/var_unserializer.re"
+#line 509 "ext/standard/var_unserializer.re"
{
*p = YYCURSOR;
INIT_PZVAL(*rval);
ZVAL_NULL(*rval);
return 1;
}
-#line 1145 "ext/standard/var_unserializer.c"
+#line 1172 "ext/standard/var_unserializer.c"
yy89:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1164,7 +1191,7 @@ yy91:
if (yych <= '9') goto yy91;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 461 "ext/standard/var_unserializer.re"
+#line 486 "ext/standard/var_unserializer.re"
{
long id;
@@ -1179,7 +1206,7 @@ yy91:
if (*rval == *rval_ref) return 0;
if (*rval != NULL) {
- zval_ptr_dtor(rval);
+ var_push_dtor_no_addref(var_hash, rval);
}
*rval = *rval_ref;
Z_ADDREF_PP(rval);
@@ -1187,7 +1214,7 @@ yy91:
return 1;
}
-#line 1191 "ext/standard/var_unserializer.c"
+#line 1218 "ext/standard/var_unserializer.c"
yy95:
yych = *++YYCURSOR;
if (yych <= ',') {
@@ -1210,7 +1237,7 @@ yy97:
if (yych <= '9') goto yy97;
if (yych != ';') goto yy18;
++YYCURSOR;
-#line 440 "ext/standard/var_unserializer.re"
+#line 465 "ext/standard/var_unserializer.re"
{
long id;
@@ -1231,9 +1258,9 @@ yy97:
return 1;
}
-#line 1235 "ext/standard/var_unserializer.c"
+#line 1262 "ext/standard/var_unserializer.c"
}
-#line 787 "ext/standard/var_unserializer.re"
+#line 814 "ext/standard/var_unserializer.re"
return 0;
diff --git a/ext/standard/var_unserializer.re b/ext/standard/var_unserializer.re
index 4d99cbfd78..76c501e1b5 100644
--- a/ext/standard/var_unserializer.re
+++ b/ext/standard/var_unserializer.re
@@ -24,6 +24,7 @@
/* {{{ reference-handling for unserializer: var_* */
#define VAR_ENTRIES_MAX 1024
+#define VAR_ENTRIES_DBG 0
typedef struct {
zval *data[VAR_ENTRIES_MAX];
@@ -34,7 +35,7 @@ typedef struct {
static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
{
var_entries *var_hash = (*var_hashx)->last;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_push(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
#endif
@@ -58,7 +59,7 @@ static inline void var_push(php_unserialize_data_t *var_hashx, zval **rval)
PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
{
var_entries *var_hash = (*var_hashx)->last_dtor;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_push_dtor(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval));
#endif
@@ -80,11 +81,35 @@ PHPAPI void var_push_dtor(php_unserialize_data_t *var_hashx, zval **rval)
var_hash->data[var_hash->used_slots++] = *rval;
}
+PHPAPI void var_push_dtor_no_addref(php_unserialize_data_t *var_hashx, zval **rval)
+{
+ var_entries *var_hash = (*var_hashx)->last_dtor;
+#if VAR_ENTRIES_DBG
+ fprintf(stderr, "var_push_dtor_no_addref(%ld): %d (%d)\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(rval), Z_REFCOUNT_PP(rval));
+#endif
+
+ if (!var_hash || var_hash->used_slots == VAR_ENTRIES_MAX) {
+ var_hash = emalloc(sizeof(var_entries));
+ var_hash->used_slots = 0;
+ var_hash->next = 0;
+
+ if (!(*var_hashx)->first_dtor) {
+ (*var_hashx)->first_dtor = var_hash;
+ } else {
+ ((var_entries *) (*var_hashx)->last_dtor)->next = var_hash;
+ }
+
+ (*var_hashx)->last_dtor = var_hash;
+ }
+
+ var_hash->data[var_hash->used_slots++] = *rval;
+}
+
PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **nzval)
{
long i;
var_entries *var_hash = (*var_hashx)->first;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_replace(%ld): %d\n", var_hash?var_hash->used_slots:-1L, Z_TYPE_PP(nzval));
#endif
@@ -102,7 +127,7 @@ PHPAPI void var_replace(php_unserialize_data_t *var_hashx, zval *ozval, zval **n
static int var_access(php_unserialize_data_t *var_hashx, long id, zval ***store)
{
var_entries *var_hash = (*var_hashx)->first;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_access(%ld): %ld\n", var_hash?var_hash->used_slots:-1L, id);
#endif
@@ -125,7 +150,7 @@ PHPAPI void var_destroy(php_unserialize_data_t *var_hashx)
void *next;
long i;
var_entries *var_hash = (*var_hashx)->first;
-#if 0
+#if VAR_ENTRIES_DBG
fprintf(stderr, "var_destroy(%ld)\n", var_hash?var_hash->used_slots:-1L);
#endif
@@ -472,7 +497,7 @@ PHPAPI int php_var_unserialize(UNSERIALIZE_PARAMETER)
if (*rval == *rval_ref) return 0;
if (*rval != NULL) {
- zval_ptr_dtor(rval);
+ var_push_dtor_no_addref(var_hash, rval);
}
*rval = *rval_ref;
Z_ADDREF_PP(rval);
@@ -683,9 +708,9 @@ object ":" uiv ":" ["] {
do {
/* Try to find class directly */
- BG(serialize_lock) = 1;
+ BG(serialize_lock)++;
if (zend_lookup_class(class_name, len2, &pce TSRMLS_CC) == SUCCESS) {
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (EG(exception)) {
efree(class_name);
return 0;
@@ -693,7 +718,7 @@ object ":" uiv ":" ["] {
ce = *pce;
break;
}
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (EG(exception)) {
efree(class_name);
@@ -713,9 +738,9 @@ object ":" uiv ":" ["] {
args[0] = &arg_func_name;
MAKE_STD_ZVAL(arg_func_name);
ZVAL_STRING(arg_func_name, class_name, 1);
- BG(serialize_lock) = 1;
+ BG(serialize_lock)++;
if (call_user_function_ex(CG(function_table), NULL, user_func, &retval_ptr, 1, args, 0, NULL TSRMLS_CC) != SUCCESS) {
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (EG(exception)) {
efree(class_name);
zval_ptr_dtor(&user_func);
@@ -729,7 +754,7 @@ object ":" uiv ":" ["] {
zval_ptr_dtor(&arg_func_name);
break;
}
- BG(serialize_lock) = 0;
+ BG(serialize_lock)--;
if (retval_ptr) {
zval_ptr_dtor(&retval_ptr);
}
@@ -757,7 +782,9 @@ object ":" uiv ":" ["] {
*p = YYCURSOR;
if (custom_object) {
- int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
+ int ret;
+
+ ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
if (ret && incomplete_class) {
php_store_class_name(*rval, class_name, len2);