php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Return to Bug #60655
Patch rand_hash_resize.patch revision 2012-01-05 08:09 UTC by laruence@php.net
Patch max_input_vars.patch revision 2012-01-05 05:04 UTC by laruence@php.net
revision 2012-01-05 05:03 UTC by laruence@php.net
revision 2012-01-05 05:02 UTC by laruence@php.net
revision 2012-01-05 04:17 UTC by laruence@php.net
revision 2012-01-05 04:08 UTC by laruence@php.net

Patch max_input_vars.patch for *General Issues Bug #60655

Patch version 2012-01-05 04:17 UTC

Return to Bug #60655 | Download this patch
This patch is obsolete

Obsoleted by patches:

This patch renders other patches obsolete

Obsolete patches:

Patch Revisions:

Developer: laruence@php.net

Index: trunk/ext/standard/basic_functions.h
===================================================================
--- trunk/ext/standard/basic_functions.h	(revision 321767)
+++ trunk/ext/standard/basic_functions.h	(working copy)
@@ -212,6 +212,8 @@
 	struct {
 		void *var_hash;
 		unsigned level;
+		long max_vars;
+		long num_vars;
 	} unserialize;
 
 	/* url_scanner_ex.re */
Index: trunk/ext/standard/tests/serialize/serialization_error_001.phpt
===================================================================
--- trunk/ext/standard/tests/serialize/serialization_error_001.phpt	(revision 321767)
+++ trunk/ext/standard/tests/serialize/serialization_error_001.phpt	(working copy)
@@ -28,15 +28,15 @@
 --EXPECTF--
 *** Testing serialize()/unserialize() : error conditions ***
 
-Warning: serialize() expects exactly 1 parameter, 0 given in %s on line 16
+Warning: serialize() expects exactly 1 parameter, 0 given in %sserialization_error_001.php on line %d
 NULL
 
-Warning: unserialize() expects exactly 1 parameter, 0 given in %s on line 17
+Warning: unserialize() expects at least 1 parameter, 0 given in %sserialization_error_001.php on line %d
 bool(false)
 
-Warning: serialize() expects exactly 1 parameter, 2 given in %s on line 20
+Warning: serialize() expects exactly 1 parameter, 2 given in %sserialization_error_001.php on line %d
 NULL
 
-Warning: unserialize() expects exactly 1 parameter, 2 given in %s on line 21
+Notice: unserialize(): Error at offset 0 of 1 bytes in %sserialization_error_001.php on line %d
 bool(false)
 Done
Index: trunk/ext/standard/tests/serialize/unserialize_max_vars.phpt
===================================================================
--- trunk/ext/standard/tests/serialize/unserialize_max_vars.phpt	(revision 0)
+++ trunk/ext/standard/tests/serialize/unserialize_max_vars.phpt	(revision 0)
@@ -0,0 +1,57 @@
+--TEST--
+Test unserialize() functions with max_input_vars
+--FILE--
+<?php
+$str = serialize(array(1,2,3)); // there will be 4 items, array, and 1, 2, 3
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 4));
+
+$str = serialize(array(array(),array(2,3))); // there will be 5 items, array, and array, array, 2, 3
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+
+$obj = (object)(array(array(),array(2,3)));
+$str = serialize($obj);
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+?>
+--EXPECTF--
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+    [0] => Array
+        (
+        )
+
+    [1] => Array
+        (
+            [0] => 2
+            [1] => 3
+        )
+
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+stdClass Object
+(
+    [0] => Array
+        (
+        )
+
+    [1] => Array
+        (
+            [0] => 2
+            [1] => 3
+        )
+
+)
Index: trunk/ext/standard/var_unserializer.c
===================================================================
--- trunk/ext/standard/var_unserializer.c	(revision 321767)
+++ trunk/ext/standard/var_unserializer.c	(working copy)
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 on Sun Jan  1 10:36:31 2012 */
+/* Generated by re2c 0.13.5 on Wed Jan  4 23:12:56 2012 */
 #line 1 "ext/standard/var_unserializer.re"
 /*
   +----------------------------------------------------------------------+
@@ -276,6 +276,7 @@
 			FREE_ZVAL(key);
 			return 0;
 		}
+        --(BG(unserialize).num_vars);
 
 		if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
 			zval_dtor(key);
@@ -297,12 +298,14 @@
 			switch (Z_TYPE_P(key)) {
 			case IS_LONG:
 				if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
 				break;
 			case IS_STRING:
 				if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
@@ -411,17 +414,20 @@
 	if (YYCURSOR >= YYLIMIT) {
 		return 0;
 	}
+
+    if (BG(unserialize).max_vars && BG(unserialize).num_vars >= BG(unserialize).max_vars) {
+	    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unserialized variables exceeded %ld", BG(unserialize).max_vars);
+        return 0;
+    }
 	
 	if (var_hash && cursor[0] != 'R') {
 		var_push(var_hash, rval);
 	}
 
 	start = cursor;
-
 	
-	
 
-#line 425 "ext/standard/var_unserializer.c"
+#line 431 "ext/standard/var_unserializer.c"
 {
 	YYCTYPE yych;
 	static const unsigned char yybm[] = {
@@ -481,9 +487,9 @@
 	yych = *(YYMARKER = ++YYCURSOR);
 	if (yych == ':') goto yy95;
 yy3:
-#line 747 "ext/standard/var_unserializer.re"
+#line 766 "ext/standard/var_unserializer.re"
 	{ return 0; }
-#line 487 "ext/standard/var_unserializer.c"
+#line 493 "ext/standard/var_unserializer.c"
 yy4:
 	yych = *(YYMARKER = ++YYCURSOR);
 	if (yych == ':') goto yy89;
@@ -526,13 +532,13 @@
 	goto yy3;
 yy14:
 	++YYCURSOR;
-#line 741 "ext/standard/var_unserializer.re"
+#line 760 "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 536 "ext/standard/var_unserializer.c"
+#line 542 "ext/standard/var_unserializer.c"
 yy16:
 	yych = *++YYCURSOR;
 	goto yy3;
@@ -562,7 +568,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 624 "ext/standard/var_unserializer.re"
+#line 641 "ext/standard/var_unserializer.re"
 	{
 	size_t len, len2, len3, maxlen;
 	long elements;
@@ -661,6 +667,7 @@
 	*p = YYCURSOR;
 
 	if (custom_object) {
+    	++(BG(unserialize).num_vars);
 		int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
 
 		if (ret && incomplete_class) {
@@ -677,9 +684,10 @@
 	}
 	efree(class_name);
 
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
-#line 683 "ext/standard/var_unserializer.c"
+#line 691 "ext/standard/var_unserializer.c"
 yy25:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -704,15 +712,16 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 616 "ext/standard/var_unserializer.re"
+#line 632 "ext/standard/var_unserializer.re"
 	{
 
 	INIT_PZVAL(*rval);
 	
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU,
 			object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
 }
-#line 716 "ext/standard/var_unserializer.c"
+#line 725 "ext/standard/var_unserializer.c"
 yy32:
 	yych = *++YYCURSOR;
 	if (yych == '+') goto yy33;
@@ -733,7 +742,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '{') goto yy18;
 	++YYCURSOR;
-#line 596 "ext/standard/var_unserializer.re"
+#line 611 "ext/standard/var_unserializer.re"
 	{
 	long elements = parse_iv(start + 2);
 	/* use iv() not uiv() in order to check data range */
@@ -747,13 +756,14 @@
 
 	array_init_size(*rval, elements);
 
+    ++(BG(unserialize).num_vars);
 	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
 		return 0;
 	}
 
 	return finish_nested_data(UNSERIALIZE_PASSTHRU);
 }
-#line 757 "ext/standard/var_unserializer.c"
+#line 767 "ext/standard/var_unserializer.c"
 yy39:
 	yych = *++YYCURSOR;
 	if (yych == '+') goto yy40;
@@ -774,7 +784,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 567 "ext/standard/var_unserializer.re"
+#line 581 "ext/standard/var_unserializer.re"
 	{
 	size_t len, maxlen;
 	char *str;
@@ -801,9 +811,10 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 0);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 807 "ext/standard/var_unserializer.c"
+#line 818 "ext/standard/var_unserializer.c"
 yy46:
 	yych = *++YYCURSOR;
 	if (yych == '+') goto yy47;
@@ -824,7 +835,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 539 "ext/standard/var_unserializer.re"
+#line 552 "ext/standard/var_unserializer.re"
 	{
 	size_t len, maxlen;
 	char *str;
@@ -850,9 +861,10 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 1);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 856 "ext/standard/var_unserializer.c"
+#line 868 "ext/standard/var_unserializer.c"
 yy53:
 	yych = *++YYCURSOR;
 	if (yych <= '/') {
@@ -940,7 +952,7 @@
 	}
 yy63:
 	++YYCURSOR;
-#line 529 "ext/standard/var_unserializer.re"
+#line 541 "ext/standard/var_unserializer.re"
 	{
 #if SIZEOF_LONG == 4
 use_double:
@@ -948,9 +960,10 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 954 "ext/standard/var_unserializer.c"
+#line 967 "ext/standard/var_unserializer.c"
 yy65:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -1009,7 +1022,7 @@
 	yych = *++YYCURSOR;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 514 "ext/standard/var_unserializer.re"
+#line 525 "ext/standard/var_unserializer.re"
 	{
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
@@ -1022,9 +1035,10 @@
 		ZVAL_DOUBLE(*rval, -php_get_inf());
 	}
 
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1028 "ext/standard/var_unserializer.c"
+#line 1042 "ext/standard/var_unserializer.c"
 yy76:
 	yych = *++YYCURSOR;
 	if (yych == 'N') goto yy73;
@@ -1051,7 +1065,7 @@
 	if (yych <= '9') goto yy79;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 487 "ext/standard/var_unserializer.re"
+#line 497 "ext/standard/var_unserializer.re"
 	{
 #if SIZEOF_LONG == 4
 	int digits = YYCURSOR - start - 3;
@@ -1076,9 +1090,10 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_LONG(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1082 "ext/standard/var_unserializer.c"
+#line 1097 "ext/standard/var_unserializer.c"
 yy83:
 	yych = *++YYCURSOR;
 	if (yych <= '/') goto yy18;
@@ -1086,24 +1101,26 @@
 	yych = *++YYCURSOR;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 480 "ext/standard/var_unserializer.re"
+#line 489 "ext/standard/var_unserializer.re"
 	{
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_BOOL(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1097 "ext/standard/var_unserializer.c"
+#line 1113 "ext/standard/var_unserializer.c"
 yy87:
 	++YYCURSOR;
-#line 473 "ext/standard/var_unserializer.re"
+#line 481 "ext/standard/var_unserializer.re"
 	{
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_NULL(*rval);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1107 "ext/standard/var_unserializer.c"
+#line 1124 "ext/standard/var_unserializer.c"
 yy89:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -1126,7 +1143,7 @@
 	if (yych <= '9') goto yy91;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 450 "ext/standard/var_unserializer.re"
+#line 457 "ext/standard/var_unserializer.re"
 	{
 	long id;
 
@@ -1147,9 +1164,10 @@
 	Z_ADDREF_PP(rval);
 	Z_UNSET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1153 "ext/standard/var_unserializer.c"
+#line 1171 "ext/standard/var_unserializer.c"
 yy95:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -1172,7 +1190,7 @@
 	if (yych <= '9') goto yy97;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 429 "ext/standard/var_unserializer.re"
+#line 435 "ext/standard/var_unserializer.re"
 	{
 	long id;
 
@@ -1191,11 +1209,12 @@
 	Z_ADDREF_PP(rval);
 	Z_SET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1197 "ext/standard/var_unserializer.c"
+#line 1216 "ext/standard/var_unserializer.c"
 }
-#line 749 "ext/standard/var_unserializer.re"
+#line 768 "ext/standard/var_unserializer.re"
 
 
 	return 0;
Index: trunk/ext/standard/var.c
===================================================================
--- trunk/ext/standard/var.c	(revision 321767)
+++ trunk/ext/standard/var.c	(working copy)
@@ -928,8 +928,9 @@
 	int buf_len;
 	const unsigned char *p;
 	php_unserialize_data_t var_hash;
+	long max_vars = PG(max_input_vars);
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &buf, &buf_len, &max_vars) == FAILURE) {
 		RETURN_FALSE;
 	}
 
@@ -939,10 +940,13 @@
 
 	p = (const unsigned char*) buf;
 	PHP_VAR_UNSERIALIZE_INIT(var_hash);
+	PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars);
 	if (!php_var_unserialize(&return_value, &p, p + buf_len, &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 %ld of %d bytes", (long)((char*)p - buf), buf_len);
+		if (!BG(unserialize).max_vars || BG(unserialize).num_vars < BG(unserialize).max_vars) {
+			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+		}
 		RETURN_FALSE;
 	}
 	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
Index: trunk/ext/standard/php_var.h
===================================================================
--- trunk/ext/standard/php_var.h	(revision 321767)
+++ trunk/ext/standard/php_var.h	(working copy)
@@ -95,9 +95,12 @@
 	} else { \
 		(var_hash_ptr) = (php_serialize_data_t)BG(unserialize).var_hash; \
 		++BG(unserialize).level; \
-	} \
+	}	\
+	BG(unserialize).num_vars = 0; \
 } while (0)
 
+#define PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars)  BG(unserialize).max_vars = max_vars;
+
 #define PHP_VAR_UNSERIALIZE_DESTROY(var_hash_ptr) \
 do { \
 	/* fprintf(stderr, "UNSERIALIZE_DESTROY == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */ \
Index: trunk/ext/standard/var_unserializer.re
===================================================================
--- trunk/ext/standard/var_unserializer.re	(revision 321767)
+++ trunk/ext/standard/var_unserializer.re	(working copy)
@@ -280,6 +280,7 @@
 			FREE_ZVAL(key);
 			return 0;
 		}
+        --(BG(unserialize).num_vars);
 
 		if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
 			zval_dtor(key);
@@ -301,12 +302,14 @@
 			switch (Z_TYPE_P(key)) {
 			case IS_LONG:
 				if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
 				break;
 			case IS_STRING:
 				if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
@@ -415,15 +418,18 @@
 	if (YYCURSOR >= YYLIMIT) {
 		return 0;
 	}
+
+    if (BG(unserialize).max_vars && BG(unserialize).num_vars >= BG(unserialize).max_vars) {
+	    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unserialized variables exceeded %ld", BG(unserialize).max_vars);
+        return 0;
+    }
 	
 	if (var_hash && cursor[0] != 'R') {
 		var_push(var_hash, rval);
 	}
 
 	start = cursor;
-
 	
-	
 /*!re2c
 
 "R:" iv ";"		{
@@ -444,6 +450,7 @@
 	Z_ADDREF_PP(rval);
 	Z_SET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -467,6 +474,7 @@
 	Z_ADDREF_PP(rval);
 	Z_UNSET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -474,6 +482,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_NULL(*rval);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -481,6 +490,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_BOOL(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -508,6 +518,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_LONG(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -523,6 +534,7 @@
 		ZVAL_DOUBLE(*rval, -php_get_inf());
 	}
 
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -533,6 +545,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -561,6 +574,7 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 1);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -590,6 +604,7 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 0);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -606,6 +621,7 @@
 
 	array_init_size(*rval, elements);
 
+    ++(BG(unserialize).num_vars);
 	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
 		return 0;
 	}
@@ -617,6 +633,7 @@
 
 	INIT_PZVAL(*rval);
 	
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU,
 			object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
 }
@@ -719,6 +736,7 @@
 	*p = YYCURSOR;
 
 	if (custom_object) {
+    	++(BG(unserialize).num_vars);
 		int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
 
 		if (ret && incomplete_class) {
@@ -735,6 +753,7 @@
 	}
 	efree(class_name);
 
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
 
Index: trunk/ext/json/json.c
===================================================================
--- trunk/ext/json/json.c	(revision 321767)
+++ trunk/ext/json/json.c	(working copy)
@@ -99,6 +99,7 @@
 
 	REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
+	REGISTER_LONG_CONSTANT("JSON_ERROR_MAX_VARS", PHP_JSON_ERROR_MAX_VARS, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
@@ -602,7 +603,7 @@
 }
 /* }}} */
 
-PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth, long max_vars TSRMLS_DC) /* {{{ */
 {
 	int utf16_len;
 	zval *z;
@@ -627,7 +628,7 @@
 	}
 
 	ALLOC_INIT_ZVAL(z);
-	jp = new_JSON_parser(depth);
+	jp = new_JSON_parser(depth, max_vars);
 	if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) {
 		*return_value = *z;
 	}
@@ -671,7 +672,6 @@
 }
 /* }}} */
 
-
 /* {{{ proto string json_encode(mixed data [, int options])
    Returns the JSON representation of a value */
 static PHP_FUNCTION(json_encode)
@@ -703,8 +703,9 @@
 	zend_bool assoc = 0; /* return JS objects as PHP objects by default */
 	long depth = JSON_PARSER_DEFAULT_DEPTH;
 	long options = 0;
+	long max_vars = PG(max_input_vars);
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|blll", &str, &str_len, &assoc, &depth, &max_vars, &options) == FAILURE) {
 		return;
 	}
 
@@ -721,7 +722,7 @@
 		options &= ~PHP_JSON_OBJECT_AS_ARRAY;
 	}
 
-	php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC);
+	php_json_decode_ex(return_value, str, str_len, options, depth, max_vars TSRMLS_CC);
 }
 /* }}} */
 
Index: trunk/ext/json/tests/008.phpt
===================================================================
--- trunk/ext/json/tests/008.phpt	(revision 321767)
+++ trunk/ext/json/tests/008.phpt	(working copy)
@@ -7,7 +7,7 @@
 $json = '{"largenum":123456789012345678901234567890}';
 $x = json_decode($json);
 var_dump($x->largenum);
-$x = json_decode($json, false, 512, JSON_BIGINT_AS_STRING);
+$x = json_decode($json, false, 512, 1000, JSON_BIGINT_AS_STRING);
 var_dump($x->largenum);
 echo "Done\n";
 ?>
Index: trunk/ext/json/tests/max_input_vars.phpt
===================================================================
--- trunk/ext/json/tests/max_input_vars.phpt	(revision 0)
+++ trunk/ext/json/tests/max_input_vars.phpt	(revision 0)
@@ -0,0 +1,40 @@
+--TEST--
+json_decode() with max_input_vars
+--SKIPIF--
+<?php if (!extension_loaded("json")) print "skip"; ?>
+--FILE--
+<?php
+
+$a = array(1,2,3,4); //an array, and 1,2,3,4 total 5 elements
+$str = json_encode($a);
+
+print_r(json_decode($str, false, 512, 4));
+var_dump(json_last_error() == JSON_ERROR_MAX_VARS);
+print_r(json_decode($str, false, 512, 5));
+
+$a = array(1,array(1),3); //an array, 1, an array, 1, 3 total 5 elements
+$str = json_encode($a);
+print_r(json_decode($str, true, 512, 4));
+var_dump(json_last_error() == JSON_ERROR_MAX_VARS);
+print_r(json_decode($str, true, 512, 5));
+?>
+--EXPECT--
+bool(true)
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+    [3] => 4
+)
+bool(true)
+Array
+(
+    [0] => 1
+    [1] => Array
+        (
+            [0] => 1
+        )
+
+    [2] => 3
+)
Index: trunk/ext/json/tests/json_decode_error.phpt
===================================================================
--- trunk/ext/json/tests/json_decode_error.phpt	(revision 321767)
+++ trunk/ext/json/tests/json_decode_error.phpt	(working copy)
@@ -20,7 +20,7 @@
 
 echo "\n-- Testing json_decode() function with more than expected no. of arguments --\n";
 $extra_arg = 10;
-var_dump( json_decode('"abc"', TRUE, 512, 0, $extra_arg) );
+var_dump( json_decode('"abc"', TRUE, 512, 0, 1000, $extra_arg) );
 
 ?>
 ===Done===
@@ -34,6 +34,6 @@
 
 -- Testing json_decode() function with more than expected no. of arguments --
 
-Warning: json_decode() expects at most 4 parameters, 5 given in %s on line %d
+Warning: json_decode() expects at most 5 parameters, 6 given in %s on line %d
 NULL
 ===Done===
Index: trunk/ext/json/JSON_parser.c
===================================================================
--- trunk/ext/json/JSON_parser.c	(revision 321767)
+++ trunk/ext/json/JSON_parser.c	(working copy)
@@ -239,11 +239,12 @@
     JSON_checker_char will delete the JSON_checker object if it sees an error.
 */
 JSON_parser
-new_JSON_parser(int depth)
+new_JSON_parser(int depth, long max_vars)
 {
     JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct));
     jp->state = GO;
     jp->depth = depth;
+	jp->max_vars = max_vars;
     jp->top = -1;
 	jp->error_code = PHP_JSON_ERROR_NONE;
     jp->stack = (int*)ecalloc(depth, sizeof(int));
@@ -443,6 +444,7 @@
     int next_state;  /* the next state */
     int the_index;
     int assoc = options & PHP_JSON_OBJECT_AS_ARRAY;
+	long num_vars = 1; /* the container is also counted in */
 
     smart_str buf = {0};
     smart_str key = {0};
@@ -453,6 +455,11 @@
 	JSON_RESET_TYPE();
 
     for (the_index = 0; the_index < length; the_index += 1) {
+		if (num_vars >= jp->max_vars) {
+			jp->error_code = PHP_JSON_ERROR_MAX_VARS;
+			FREE_BUFFERS();
+			return false;
+		}
         next_char = utf16_json[the_index];
 		if (next_char >= 128) {
 			next_class = C_ETC;
@@ -555,8 +562,10 @@
                     } else {
                         add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
                     }
+
                     key.len = 0;
                     buf.len = 0;
+					++num_vars;
                     JSON_RESET_TYPE();
                 }
 
@@ -574,10 +583,15 @@
                 {
                     zval *mval;
                     smart_str_0(&buf);
-
+					if (zend_hash_num_elements(HASH_OF(jp->the_zstack[jp->top])) >= jp->max_vars) {
+						buf.len = 0;
+						JSON_RESET_TYPE();
+						continue;
+					}
                     json_create_zval(&mval, &buf, type, options);
                     add_next_index_zval(jp->the_zstack[jp->top], mval);
                     buf.len = 0;
+					++num_vars;
                     JSON_RESET_TYPE();
                 }
 
@@ -615,6 +629,7 @@
 
                     if (jp->top > 1) {
                         attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
+						++num_vars;
                     }
 
                     JSON_RESET_TYPE();
@@ -643,6 +658,7 @@
 
                     if (jp->top > 1) {
                         attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
+				        ++num_vars;
                     }
 
                     JSON_RESET_TYPE();
@@ -700,6 +716,7 @@
                                 } else {
                                     add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
                                 }
+								++num_vars;
                                 key.len = 0;
                             }
                             jp->state = KE;
@@ -708,6 +725,7 @@
                     case MODE_ARRAY:
                         if (type != -1) {
                             add_next_index_zval(jp->the_zstack[jp->top], mval);
+					        ++num_vars;
                         }
                         jp->state = VA;
                         break;
Index: trunk/ext/json/php_json.h
===================================================================
--- trunk/ext/json/php_json.h	(revision 321767)
+++ trunk/ext/json/php_json.h	(working copy)
@@ -49,7 +49,7 @@
 #endif
 
 PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC);
-PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC);
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth, long max_vars TSRMLS_DC);
 extern zend_class_entry *php_json_serializable_ce;
 
 
@@ -74,7 +74,7 @@
 
 static inline void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC)
 {
-	php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth TSRMLS_CC);
+	php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth, 0 TSRMLS_CC);
 }
 
 
Index: trunk/ext/json/JSON_parser.h
===================================================================
--- trunk/ext/json/JSON_parser.h	(revision 321767)
+++ trunk/ext/json/JSON_parser.h	(working copy)
@@ -15,20 +15,22 @@
     int top;
 	int error_code;
     int* stack;
+	long max_vars;
     zval **the_zstack;
     zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH];
 } * JSON_parser;
 
 enum error_codes {
 	PHP_JSON_ERROR_NONE = 0,
-    PHP_JSON_ERROR_DEPTH, 
+    PHP_JSON_ERROR_DEPTH,
     PHP_JSON_ERROR_STATE_MISMATCH,  
     PHP_JSON_ERROR_CTRL_CHAR,   
     PHP_JSON_ERROR_SYNTAX,
-    PHP_JSON_ERROR_UTF8
+    PHP_JSON_ERROR_UTF8,
+	PHP_JSON_ERROR_MAX_VARS,
 };
 
-extern JSON_parser new_JSON_parser(int depth);
+extern JSON_parser new_JSON_parser(int depth, long max_vars);
 extern int parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC);
 extern int free_JSON_parser(JSON_parser jp);
 
Index: trunk/main/rfc1867.c
===================================================================
--- trunk/main/rfc1867.c	(revision 321767)
+++ trunk/main/rfc1867.c	(working copy)
@@ -686,6 +686,7 @@
 	zend_llist header;
 	void *event_extra_data = NULL;
 	unsigned int llen = 0;
+	long num_vars = 0;
 	int upload_cnt = INI_INT("max_file_uploads");
 	const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
 	php_rfc1867_getword_t getword;
@@ -896,6 +897,11 @@
 
 				efree(param);
 				efree(value);
+				++num_vars;
+				if (PG(max_input_vars) && num_vars >= PG(max_input_vars)) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Post variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+					goto fileupload_done;
+				}
 				continue;
 			}
 
Index: trunk/main/php_variables.c
===================================================================
--- trunk/main/php_variables.c	(revision 321767)
+++ trunk/main/php_variables.c	(working copy)
@@ -178,15 +178,10 @@
 			} else {
 				escaped_index = index;
 				if (zend_symtable_find(symtable1, escaped_index, index_len + 1, (void **) &gpc_element_p) == FAILURE
-					|| Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
-					if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
-						if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
-							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
-						}
-						MAKE_STD_ZVAL(gpc_element);
-						array_init(gpc_element);
-						zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
-					}
+						|| Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
+					MAKE_STD_ZVAL(gpc_element);
+					array_init(gpc_element);
+					zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
 				}
 				if (index != escaped_index) {
 					efree(escaped_index);
@@ -225,14 +220,7 @@
 				zend_symtable_exists(symtable1, escaped_index, index_len + 1)) {
 				zval_ptr_dtor(&gpc_element);
 			} else {
-				if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
-					if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
-						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
-					}
-					zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
-				} else {
-					zval_ptr_dtor(&gpc_element);
-				}
+				zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
 			}
 			if (escaped_index != index) {
 				efree(escaped_index);
@@ -246,6 +234,7 @@
 {
 	char *var, *val, *e, *s, *p;
 	zval *array_ptr = (zval *) arg;
+	long num_vars = 0;
 
 	if (SG(request_info).post_data == NULL) {
 		return;
@@ -270,6 +259,11 @@
 			}
 			efree(val);
 		}
+		++num_vars;
+		if (PG(max_input_vars) && num_vars >= PG(max_input_vars)) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Post variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+			return;
+		}
 		s = p + 1;
 	}
 	if (s < e) {
Index: branches/PHP_5_3/main/rfc1867.c
===================================================================
--- branches/PHP_5_3/main/rfc1867.c	(revision 321767)
+++ branches/PHP_5_3/main/rfc1867.c	(working copy)
@@ -779,6 +779,7 @@
 	void *event_extra_data = NULL;
 	int llen = 0;
 	int upload_cnt = INI_INT("max_file_uploads");
+	long total_num_vars = 0;
 
 	if (SG(post_max_size) > 0 && SG(request_info).content_length > SG(post_max_size)) {
 		sapi_module.sapi_error(E_WARNING, "POST Content-Length of %ld bytes exceeds the limit of %ld bytes", SG(request_info).content_length, SG(post_max_size));
@@ -962,6 +963,11 @@
 
 				efree(param);
 				efree(value);
+				++total_num_vars;
+				if (PG(max_input_vars) && total_num_vars >= PG(max_input_vars)) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Post variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+					goto fileupload_done;
+				}
 				continue;
 			}
 
Index: branches/PHP_5_3/main/php_version.h
===================================================================
--- branches/PHP_5_3/main/php_version.h	(revision 321767)
+++ branches/PHP_5_3/main/php_version.h	(working copy)
@@ -2,7 +2,7 @@
 /* edit configure.in to change version number */
 #define PHP_MAJOR_VERSION 5
 #define PHP_MINOR_VERSION 3
-#define PHP_RELEASE_VERSION 9
+#define PHP_RELEASE_VERSION 7
 #define PHP_EXTRA_VERSION "RC5-dev"
-#define PHP_VERSION "5.3.9RC5-dev"
-#define PHP_VERSION_ID 50309
+#define PHP_VERSION "5.3.7RC5-dev"
+#define PHP_VERSION_ID 50307
Index: branches/PHP_5_3/main/php_variables.c
===================================================================
--- branches/PHP_5_3/main/php_variables.c	(revision 321767)
+++ branches/PHP_5_3/main/php_variables.c	(working copy)
@@ -191,14 +191,9 @@
 				}
 				if (zend_symtable_find(symtable1, escaped_index, index_len + 1, (void **) &gpc_element_p) == FAILURE
 					|| Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
-					if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
-						if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
-							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
-						}
-						MAKE_STD_ZVAL(gpc_element);
-						array_init(gpc_element);
-						zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
-					}
+					MAKE_STD_ZVAL(gpc_element);
+					array_init(gpc_element);
+					zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
 				}
 				if (index != escaped_index) {
 					efree(escaped_index);
@@ -241,14 +236,7 @@
 				zend_symtable_exists(symtable1, escaped_index, index_len + 1)) {
 				zval_ptr_dtor(&gpc_element);
 			} else {
-				if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
-					if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
-						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
-					}
-					zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
-				} else {
-					zval_ptr_dtor(&gpc_element);
-				}
+				zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
 			}
 			if (escaped_index != index) {
 				efree(escaped_index);
@@ -262,6 +250,7 @@
 {
 	char *var, *val, *e, *s, *p;
 	zval *array_ptr = (zval *) arg;
+	long num_vars = 0;
 
 	if (SG(request_info).post_data == NULL) {
 		return;
@@ -286,6 +275,10 @@
 			}
 			efree(val);
 		}
+		if (++num_vars >= PG(max_input_vars)) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Post variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+			return;
+		}
 		s = p + 1;
 	}
 	if (s < e) {
Index: branches/PHP_5_4/ext/standard/basic_functions.h
===================================================================
--- branches/PHP_5_4/ext/standard/basic_functions.h	(revision 321767)
+++ branches/PHP_5_4/ext/standard/basic_functions.h	(working copy)
@@ -212,6 +212,8 @@
 	struct {
 		void *var_hash;
 		unsigned level;
+		long max_vars;
+		long num_vars;
 	} unserialize;
 
 	/* url_scanner_ex.re */
Index: branches/PHP_5_4/ext/standard/tests/serialize/serialization_error_001.phpt
===================================================================
--- branches/PHP_5_4/ext/standard/tests/serialize/serialization_error_001.phpt	(revision 321767)
+++ branches/PHP_5_4/ext/standard/tests/serialize/serialization_error_001.phpt	(working copy)
@@ -28,15 +28,15 @@
 --EXPECTF--
 *** Testing serialize()/unserialize() : error conditions ***
 
-Warning: serialize() expects exactly 1 parameter, 0 given in %s on line 16
+Warning: serialize() expects exactly 1 parameter, 0 given in %sserialization_error_001.php on line %d
 NULL
 
-Warning: unserialize() expects exactly 1 parameter, 0 given in %s on line 17
+Warning: unserialize() expects at least 1 parameter, 0 given in %sserialization_error_001.php on line %d
 bool(false)
 
-Warning: serialize() expects exactly 1 parameter, 2 given in %s on line 20
+Warning: serialize() expects exactly 1 parameter, 2 given in %sserialization_error_001.php on line %d
 NULL
 
-Warning: unserialize() expects exactly 1 parameter, 2 given in %s on line 21
+Notice: unserialize(): Error at offset 0 of 1 bytes in %sserialization_error_001.php on line %d
 bool(false)
 Done
Index: branches/PHP_5_4/ext/standard/tests/serialize/unserialize_max_vars.phpt
===================================================================
--- branches/PHP_5_4/ext/standard/tests/serialize/unserialize_max_vars.phpt	(revision 0)
+++ branches/PHP_5_4/ext/standard/tests/serialize/unserialize_max_vars.phpt	(revision 0)
@@ -0,0 +1,57 @@
+--TEST--
+Test unserialize() functions with max_input_vars
+--FILE--
+<?php
+$str = serialize(array(1,2,3)); // there will be 4 items, array, and 1, 2, 3
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 4));
+
+$str = serialize(array(array(),array(2,3))); // there will be 5 items, array, and array, array, 2, 3
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+
+$obj = (object)(array(array(),array(2,3)));
+$str = serialize($obj);
+
+print_r(unserialize($str, 3));
+print_r(unserialize($str, 5));
+?>
+--EXPECTF--
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+    [0] => 1
+    [1] => 2
+    [2] => 3
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+Array
+(
+    [0] => Array
+        (
+        )
+
+    [1] => Array
+        (
+            [0] => 2
+            [1] => 3
+        )
+
+)
+
+Warning: unserialize(): Unserialized variables exceeded 3 in %sunserialize_max_vars.php on line %d
+stdClass Object
+(
+    [0] => Array
+        (
+        )
+
+    [1] => Array
+        (
+            [0] => 2
+            [1] => 3
+        )
+
+)
Index: branches/PHP_5_4/ext/standard/var_unserializer.c
===================================================================
--- branches/PHP_5_4/ext/standard/var_unserializer.c	(revision 321767)
+++ branches/PHP_5_4/ext/standard/var_unserializer.c	(working copy)
@@ -1,4 +1,4 @@
-/* Generated by re2c 0.13.5 on Wed Nov  9 19:37:48 2011 */
+/* Generated by re2c 0.13.5 on Wed Jan  4 23:12:56 2012 */
 #line 1 "ext/standard/var_unserializer.re"
 /*
   +----------------------------------------------------------------------+
@@ -276,6 +276,7 @@
 			FREE_ZVAL(key);
 			return 0;
 		}
+        --(BG(unserialize).num_vars);
 
 		if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
 			zval_dtor(key);
@@ -297,12 +298,14 @@
 			switch (Z_TYPE_P(key)) {
 			case IS_LONG:
 				if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
 				break;
 			case IS_STRING:
 				if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
@@ -411,17 +414,20 @@
 	if (YYCURSOR >= YYLIMIT) {
 		return 0;
 	}
+
+    if (BG(unserialize).max_vars && BG(unserialize).num_vars >= BG(unserialize).max_vars) {
+	    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unserialized variables exceeded %ld", BG(unserialize).max_vars);
+        return 0;
+    }
 	
 	if (var_hash && cursor[0] != 'R') {
 		var_push(var_hash, rval);
 	}
 
 	start = cursor;
-
 	
-	
 
-#line 425 "ext/standard/var_unserializer.c"
+#line 431 "ext/standard/var_unserializer.c"
 {
 	YYCTYPE yych;
 	static const unsigned char yybm[] = {
@@ -481,9 +487,9 @@
 	yych = *(YYMARKER = ++YYCURSOR);
 	if (yych == ':') goto yy95;
 yy3:
-#line 747 "ext/standard/var_unserializer.re"
+#line 766 "ext/standard/var_unserializer.re"
 	{ return 0; }
-#line 487 "ext/standard/var_unserializer.c"
+#line 493 "ext/standard/var_unserializer.c"
 yy4:
 	yych = *(YYMARKER = ++YYCURSOR);
 	if (yych == ':') goto yy89;
@@ -526,13 +532,13 @@
 	goto yy3;
 yy14:
 	++YYCURSOR;
-#line 741 "ext/standard/var_unserializer.re"
+#line 760 "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 536 "ext/standard/var_unserializer.c"
+#line 542 "ext/standard/var_unserializer.c"
 yy16:
 	yych = *++YYCURSOR;
 	goto yy3;
@@ -562,7 +568,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 624 "ext/standard/var_unserializer.re"
+#line 641 "ext/standard/var_unserializer.re"
 	{
 	size_t len, len2, len3, maxlen;
 	long elements;
@@ -661,6 +667,7 @@
 	*p = YYCURSOR;
 
 	if (custom_object) {
+    	++(BG(unserialize).num_vars);
 		int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
 
 		if (ret && incomplete_class) {
@@ -677,9 +684,10 @@
 	}
 	efree(class_name);
 
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
-#line 683 "ext/standard/var_unserializer.c"
+#line 691 "ext/standard/var_unserializer.c"
 yy25:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -704,15 +712,16 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 616 "ext/standard/var_unserializer.re"
+#line 632 "ext/standard/var_unserializer.re"
 	{
 
 	INIT_PZVAL(*rval);
 	
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU,
 			object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
 }
-#line 716 "ext/standard/var_unserializer.c"
+#line 725 "ext/standard/var_unserializer.c"
 yy32:
 	yych = *++YYCURSOR;
 	if (yych == '+') goto yy33;
@@ -733,7 +742,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '{') goto yy18;
 	++YYCURSOR;
-#line 596 "ext/standard/var_unserializer.re"
+#line 611 "ext/standard/var_unserializer.re"
 	{
 	long elements = parse_iv(start + 2);
 	/* use iv() not uiv() in order to check data range */
@@ -747,13 +756,14 @@
 
 	array_init_size(*rval, elements);
 
+    ++(BG(unserialize).num_vars);
 	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
 		return 0;
 	}
 
 	return finish_nested_data(UNSERIALIZE_PASSTHRU);
 }
-#line 757 "ext/standard/var_unserializer.c"
+#line 767 "ext/standard/var_unserializer.c"
 yy39:
 	yych = *++YYCURSOR;
 	if (yych == '+') goto yy40;
@@ -774,7 +784,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 567 "ext/standard/var_unserializer.re"
+#line 581 "ext/standard/var_unserializer.re"
 	{
 	size_t len, maxlen;
 	char *str;
@@ -801,9 +811,10 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 0);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 807 "ext/standard/var_unserializer.c"
+#line 818 "ext/standard/var_unserializer.c"
 yy46:
 	yych = *++YYCURSOR;
 	if (yych == '+') goto yy47;
@@ -824,7 +835,7 @@
 	yych = *++YYCURSOR;
 	if (yych != '"') goto yy18;
 	++YYCURSOR;
-#line 539 "ext/standard/var_unserializer.re"
+#line 552 "ext/standard/var_unserializer.re"
 	{
 	size_t len, maxlen;
 	char *str;
@@ -850,9 +861,10 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 1);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 856 "ext/standard/var_unserializer.c"
+#line 868 "ext/standard/var_unserializer.c"
 yy53:
 	yych = *++YYCURSOR;
 	if (yych <= '/') {
@@ -940,7 +952,7 @@
 	}
 yy63:
 	++YYCURSOR;
-#line 529 "ext/standard/var_unserializer.re"
+#line 541 "ext/standard/var_unserializer.re"
 	{
 #if SIZEOF_LONG == 4
 use_double:
@@ -948,9 +960,10 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 954 "ext/standard/var_unserializer.c"
+#line 967 "ext/standard/var_unserializer.c"
 yy65:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -1009,7 +1022,7 @@
 	yych = *++YYCURSOR;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 514 "ext/standard/var_unserializer.re"
+#line 525 "ext/standard/var_unserializer.re"
 	{
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
@@ -1022,9 +1035,10 @@
 		ZVAL_DOUBLE(*rval, -php_get_inf());
 	}
 
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1028 "ext/standard/var_unserializer.c"
+#line 1042 "ext/standard/var_unserializer.c"
 yy76:
 	yych = *++YYCURSOR;
 	if (yych == 'N') goto yy73;
@@ -1051,7 +1065,7 @@
 	if (yych <= '9') goto yy79;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 487 "ext/standard/var_unserializer.re"
+#line 497 "ext/standard/var_unserializer.re"
 	{
 #if SIZEOF_LONG == 4
 	int digits = YYCURSOR - start - 3;
@@ -1076,9 +1090,10 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_LONG(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1082 "ext/standard/var_unserializer.c"
+#line 1097 "ext/standard/var_unserializer.c"
 yy83:
 	yych = *++YYCURSOR;
 	if (yych <= '/') goto yy18;
@@ -1086,24 +1101,26 @@
 	yych = *++YYCURSOR;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 480 "ext/standard/var_unserializer.re"
+#line 489 "ext/standard/var_unserializer.re"
 	{
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_BOOL(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1097 "ext/standard/var_unserializer.c"
+#line 1113 "ext/standard/var_unserializer.c"
 yy87:
 	++YYCURSOR;
-#line 473 "ext/standard/var_unserializer.re"
+#line 481 "ext/standard/var_unserializer.re"
 	{
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_NULL(*rval);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1107 "ext/standard/var_unserializer.c"
+#line 1124 "ext/standard/var_unserializer.c"
 yy89:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -1126,7 +1143,7 @@
 	if (yych <= '9') goto yy91;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 450 "ext/standard/var_unserializer.re"
+#line 457 "ext/standard/var_unserializer.re"
 	{
 	long id;
 
@@ -1147,9 +1164,10 @@
 	Z_ADDREF_PP(rval);
 	Z_UNSET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1153 "ext/standard/var_unserializer.c"
+#line 1171 "ext/standard/var_unserializer.c"
 yy95:
 	yych = *++YYCURSOR;
 	if (yych <= ',') {
@@ -1172,7 +1190,7 @@
 	if (yych <= '9') goto yy97;
 	if (yych != ';') goto yy18;
 	++YYCURSOR;
-#line 429 "ext/standard/var_unserializer.re"
+#line 435 "ext/standard/var_unserializer.re"
 	{
 	long id;
 
@@ -1191,11 +1209,12 @@
 	Z_ADDREF_PP(rval);
 	Z_SET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
-#line 1197 "ext/standard/var_unserializer.c"
+#line 1216 "ext/standard/var_unserializer.c"
 }
-#line 749 "ext/standard/var_unserializer.re"
+#line 768 "ext/standard/var_unserializer.re"
 
 
 	return 0;
Index: branches/PHP_5_4/ext/standard/var.c
===================================================================
--- branches/PHP_5_4/ext/standard/var.c	(revision 321767)
+++ branches/PHP_5_4/ext/standard/var.c	(working copy)
@@ -928,8 +928,9 @@
 	int buf_len;
 	const unsigned char *p;
 	php_unserialize_data_t var_hash;
+	long max_vars = PG(max_input_vars);
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &buf, &buf_len) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &buf, &buf_len, &max_vars) == FAILURE) {
 		RETURN_FALSE;
 	}
 
@@ -939,10 +940,13 @@
 
 	p = (const unsigned char*) buf;
 	PHP_VAR_UNSERIALIZE_INIT(var_hash);
+	PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars);
 	if (!php_var_unserialize(&return_value, &p, p + buf_len, &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 %ld of %d bytes", (long)((char*)p - buf), buf_len);
+		if (!BG(unserialize).max_vars || BG(unserialize).num_vars < BG(unserialize).max_vars) {
+			php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Error at offset %ld of %d bytes", (long)((char*)p - buf), buf_len);
+		}
 		RETURN_FALSE;
 	}
 	PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
Index: branches/PHP_5_4/ext/standard/php_var.h
===================================================================
--- branches/PHP_5_4/ext/standard/php_var.h	(revision 321767)
+++ branches/PHP_5_4/ext/standard/php_var.h	(working copy)
@@ -95,9 +95,12 @@
 	} else { \
 		(var_hash_ptr) = (php_serialize_data_t)BG(unserialize).var_hash; \
 		++BG(unserialize).level; \
-	} \
+	}	\
+	BG(unserialize).num_vars = 0; \
 } while (0)
 
+#define PHP_VAR_UNSERIALIZE_MAX_VARS(max_vars)  BG(unserialize).max_vars = max_vars;
+
 #define PHP_VAR_UNSERIALIZE_DESTROY(var_hash_ptr) \
 do { \
 	/* fprintf(stderr, "UNSERIALIZE_DESTROY == lock: %u, level: %u\n", BG(serialize_lock), BG(unserialize).level); */ \
Index: branches/PHP_5_4/ext/standard/var_unserializer.re
===================================================================
--- branches/PHP_5_4/ext/standard/var_unserializer.re	(revision 321767)
+++ branches/PHP_5_4/ext/standard/var_unserializer.re	(working copy)
@@ -280,6 +280,7 @@
 			FREE_ZVAL(key);
 			return 0;
 		}
+        --(BG(unserialize).num_vars);
 
 		if (Z_TYPE_P(key) != IS_LONG && Z_TYPE_P(key) != IS_STRING) {
 			zval_dtor(key);
@@ -301,12 +302,14 @@
 			switch (Z_TYPE_P(key)) {
 			case IS_LONG:
 				if (zend_hash_index_find(ht, Z_LVAL_P(key), (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_hash_index_update(ht, Z_LVAL_P(key), &data, sizeof(data), NULL);
 				break;
 			case IS_STRING:
 				if (zend_symtable_find(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, (void **)&old_data)==SUCCESS) {
+                    --(BG(unserialize).num_vars);
 					var_push_dtor(var_hash, old_data);
 				}
 				zend_symtable_update(ht, Z_STRVAL_P(key), Z_STRLEN_P(key) + 1, &data, sizeof(data), NULL);
@@ -415,15 +418,18 @@
 	if (YYCURSOR >= YYLIMIT) {
 		return 0;
 	}
+
+    if (BG(unserialize).max_vars && BG(unserialize).num_vars >= BG(unserialize).max_vars) {
+	    php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unserialized variables exceeded %ld", BG(unserialize).max_vars);
+        return 0;
+    }
 	
 	if (var_hash && cursor[0] != 'R') {
 		var_push(var_hash, rval);
 	}
 
 	start = cursor;
-
 	
-	
 /*!re2c
 
 "R:" iv ";"		{
@@ -444,6 +450,7 @@
 	Z_ADDREF_PP(rval);
 	Z_SET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -467,6 +474,7 @@
 	Z_ADDREF_PP(rval);
 	Z_UNSET_ISREF_PP(rval);
 	
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -474,6 +482,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_NULL(*rval);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -481,6 +490,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_BOOL(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -508,6 +518,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_LONG(*rval, parse_iv(start + 2));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -523,6 +534,7 @@
 		ZVAL_DOUBLE(*rval, -php_get_inf());
 	}
 
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -533,6 +545,7 @@
 	*p = YYCURSOR;
 	INIT_PZVAL(*rval);
 	ZVAL_DOUBLE(*rval, zend_strtod((const char *)start + 2, NULL));
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -561,6 +574,7 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 1);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -590,6 +604,7 @@
 
 	INIT_PZVAL(*rval);
 	ZVAL_STRINGL(*rval, str, len, 0);
+    ++(BG(unserialize).num_vars);
 	return 1;
 }
 
@@ -606,6 +621,7 @@
 
 	array_init_size(*rval, elements);
 
+    ++(BG(unserialize).num_vars);
 	if (!process_nested_data(UNSERIALIZE_PASSTHRU, Z_ARRVAL_PP(rval), elements, 0)) {
 		return 0;
 	}
@@ -617,6 +633,7 @@
 
 	INIT_PZVAL(*rval);
 	
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU,
 			object_common1(UNSERIALIZE_PASSTHRU, ZEND_STANDARD_CLASS_DEF_PTR));
 }
@@ -719,6 +736,7 @@
 	*p = YYCURSOR;
 
 	if (custom_object) {
+    	++(BG(unserialize).num_vars);
 		int ret = object_custom(UNSERIALIZE_PASSTHRU, ce);
 
 		if (ret && incomplete_class) {
@@ -735,6 +753,7 @@
 	}
 	efree(class_name);
 
+    ++(BG(unserialize).num_vars);
 	return object_common2(UNSERIALIZE_PASSTHRU, elements);
 }
 
Index: branches/PHP_5_4/ext/json/json.c
===================================================================
--- branches/PHP_5_4/ext/json/json.c	(revision 321767)
+++ branches/PHP_5_4/ext/json/json.c	(working copy)
@@ -99,6 +99,7 @@
 
 	REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
+	REGISTER_LONG_CONSTANT("JSON_ERROR_MAX_VARS", PHP_JSON_ERROR_MAX_VARS, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
 	REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
@@ -602,7 +603,7 @@
 }
 /* }}} */
 
-PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC) /* {{{ */
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth, long max_vars TSRMLS_DC) /* {{{ */
 {
 	int utf16_len;
 	zval *z;
@@ -627,7 +628,7 @@
 	}
 
 	ALLOC_INIT_ZVAL(z);
-	jp = new_JSON_parser(depth);
+	jp = new_JSON_parser(depth, max_vars);
 	if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) {
 		*return_value = *z;
 	}
@@ -671,7 +672,6 @@
 }
 /* }}} */
 
-
 /* {{{ proto string json_encode(mixed data [, int options])
    Returns the JSON representation of a value */
 static PHP_FUNCTION(json_encode)
@@ -703,8 +703,9 @@
 	zend_bool assoc = 0; /* return JS objects as PHP objects by default */
 	long depth = JSON_PARSER_DEFAULT_DEPTH;
 	long options = 0;
+	long max_vars = PG(max_input_vars);
 
-	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str, &str_len, &assoc, &depth, &options) == FAILURE) {
+	if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|blll", &str, &str_len, &assoc, &depth, &max_vars, &options) == FAILURE) {
 		return;
 	}
 
@@ -721,7 +722,7 @@
 		options &= ~PHP_JSON_OBJECT_AS_ARRAY;
 	}
 
-	php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC);
+	php_json_decode_ex(return_value, str, str_len, options, depth, max_vars TSRMLS_CC);
 }
 /* }}} */
 
Index: branches/PHP_5_4/ext/json/tests/008.phpt
===================================================================
--- branches/PHP_5_4/ext/json/tests/008.phpt	(revision 321767)
+++ branches/PHP_5_4/ext/json/tests/008.phpt	(working copy)
@@ -7,7 +7,7 @@
 $json = '{"largenum":123456789012345678901234567890}';
 $x = json_decode($json);
 var_dump($x->largenum);
-$x = json_decode($json, false, 512, JSON_BIGINT_AS_STRING);
+$x = json_decode($json, false, 512, 1000, JSON_BIGINT_AS_STRING);
 var_dump($x->largenum);
 echo "Done\n";
 ?>
Index: branches/PHP_5_4/ext/json/tests/json_decode_error.phpt
===================================================================
--- branches/PHP_5_4/ext/json/tests/json_decode_error.phpt	(revision 321767)
+++ branches/PHP_5_4/ext/json/tests/json_decode_error.phpt	(working copy)
@@ -20,7 +20,7 @@
 
 echo "\n-- Testing json_decode() function with more than expected no. of arguments --\n";
 $extra_arg = 10;
-var_dump( json_decode('"abc"', TRUE, 512, 0, $extra_arg) );
+var_dump( json_decode('"abc"', TRUE, 512, 0, 1000, $extra_arg) );
 
 ?>
 ===Done===
@@ -34,6 +34,6 @@
 
 -- Testing json_decode() function with more than expected no. of arguments --
 
-Warning: json_decode() expects at most 4 parameters, 5 given in %s on line %d
+Warning: json_decode() expects at most 5 parameters, 6 given in %s on line %d
 NULL
 ===Done===
Index: branches/PHP_5_4/ext/json/JSON_parser.c
===================================================================
--- branches/PHP_5_4/ext/json/JSON_parser.c	(revision 321767)
+++ branches/PHP_5_4/ext/json/JSON_parser.c	(working copy)
@@ -239,11 +239,12 @@
     JSON_checker_char will delete the JSON_checker object if it sees an error.
 */
 JSON_parser
-new_JSON_parser(int depth)
+new_JSON_parser(int depth, long max_vars)
 {
     JSON_parser jp = (JSON_parser)emalloc(sizeof(struct JSON_parser_struct));
     jp->state = GO;
     jp->depth = depth;
+	jp->max_vars = max_vars;
     jp->top = -1;
 	jp->error_code = PHP_JSON_ERROR_NONE;
     jp->stack = (int*)ecalloc(depth, sizeof(int));
@@ -443,6 +444,7 @@
     int next_state;  /* the next state */
     int the_index;
     int assoc = options & PHP_JSON_OBJECT_AS_ARRAY;
+	long num_vars = 1; /* the container is also counted in */
 
     smart_str buf = {0};
     smart_str key = {0};
@@ -453,6 +455,11 @@
 	JSON_RESET_TYPE();
 
     for (the_index = 0; the_index < length; the_index += 1) {
+		if (jp->max_vars && num_vars >= jp->max_vars) {
+			jp->error_code = PHP_JSON_ERROR_MAX_VARS;
+			FREE_BUFFERS();
+			return false;
+		}
         next_char = utf16_json[the_index];
 		if (next_char >= 128) {
 			next_class = C_ETC;
@@ -555,8 +562,10 @@
                     } else {
                         add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
                     }
+
                     key.len = 0;
                     buf.len = 0;
+					++num_vars;
                     JSON_RESET_TYPE();
                 }
 
@@ -574,10 +583,10 @@
                 {
                     zval *mval;
                     smart_str_0(&buf);
-
                     json_create_zval(&mval, &buf, type, options);
                     add_next_index_zval(jp->the_zstack[jp->top], mval);
                     buf.len = 0;
+					++num_vars;
                     JSON_RESET_TYPE();
                 }
 
@@ -602,6 +611,7 @@
                     if (jp->top == 1) {
                         obj = z;
                   	} else {
+						++num_vars;
                         ALLOC_INIT_ZVAL(obj);
                     }
 
@@ -611,6 +621,7 @@
                         array_init(obj);
                     }
 
+					++num_vars;
                     jp->the_zstack[jp->top] = obj;
 
                     if (jp->top > 1) {
@@ -643,6 +654,7 @@
 
                     if (jp->top > 1) {
                         attach_zval(jp, jp->top - 1, jp->top, &key, assoc TSRMLS_CC);
+				        ++num_vars;
                     }
 
                     JSON_RESET_TYPE();
@@ -700,6 +712,7 @@
                                 } else {
                                     add_assoc_zval_ex(jp->the_zstack[jp->top], (key.len ? key.c : ""), (key.len ? (key.len + 1) : sizeof("")), mval);
                                 }
+								++num_vars;
                                 key.len = 0;
                             }
                             jp->state = KE;
@@ -708,6 +721,7 @@
                     case MODE_ARRAY:
                         if (type != -1) {
                             add_next_index_zval(jp->the_zstack[jp->top], mval);
+					        ++num_vars;
                         }
                         jp->state = VA;
                         break;
Index: branches/PHP_5_4/ext/json/php_json.h
===================================================================
--- branches/PHP_5_4/ext/json/php_json.h	(revision 321767)
+++ branches/PHP_5_4/ext/json/php_json.h	(working copy)
@@ -49,7 +49,7 @@
 #endif
 
 PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC);
-PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth TSRMLS_DC);
+PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len, int options, long depth, long max_vars TSRMLS_DC);
 extern zend_class_entry *php_json_serializable_ce;
 
 
@@ -74,7 +74,7 @@
 
 static inline void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC)
 {
-	php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth TSRMLS_CC);
+	php_json_decode_ex(return_value, str, str_len, assoc ? PHP_JSON_OBJECT_AS_ARRAY : 0, depth, 0 TSRMLS_CC);
 }
 
 
Index: branches/PHP_5_4/ext/json/JSON_parser.h
===================================================================
--- branches/PHP_5_4/ext/json/JSON_parser.h	(revision 321767)
+++ branches/PHP_5_4/ext/json/JSON_parser.h	(working copy)
@@ -15,20 +15,22 @@
     int top;
 	int error_code;
     int* stack;
+	long max_vars;
     zval **the_zstack;
     zval *the_static_zstack[JSON_PARSER_DEFAULT_DEPTH];
 } * JSON_parser;
 
 enum error_codes {
 	PHP_JSON_ERROR_NONE = 0,
-    PHP_JSON_ERROR_DEPTH, 
+    PHP_JSON_ERROR_DEPTH,
     PHP_JSON_ERROR_STATE_MISMATCH,  
     PHP_JSON_ERROR_CTRL_CHAR,   
     PHP_JSON_ERROR_SYNTAX,
-    PHP_JSON_ERROR_UTF8
+    PHP_JSON_ERROR_UTF8,
+	PHP_JSON_ERROR_MAX_VARS,
 };
 
-extern JSON_parser new_JSON_parser(int depth);
+extern JSON_parser new_JSON_parser(int depth, long max_vars);
 extern int parse_JSON_ex(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int options TSRMLS_DC);
 extern int free_JSON_parser(JSON_parser jp);
 
Index: branches/PHP_5_4/main/rfc1867.c
===================================================================
--- branches/PHP_5_4/main/rfc1867.c	(revision 321767)
+++ branches/PHP_5_4/main/rfc1867.c	(working copy)
@@ -686,6 +686,7 @@
 	zend_llist header;
 	void *event_extra_data = NULL;
 	unsigned int llen = 0;
+	long num_vars = 0;
 	int upload_cnt = INI_INT("max_file_uploads");
 	const zend_encoding *internal_encoding = zend_multibyte_get_internal_encoding(TSRMLS_C);
 	php_rfc1867_getword_t getword;
@@ -896,6 +897,11 @@
 
 				efree(param);
 				efree(value);
+				++num_vars;
+				if (PG(max_input_vars) && num_vars >= PG(max_input_vars)) {
+					php_error_docref(NULL TSRMLS_CC, E_WARNING, "Post variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+					goto fileupload_done;
+				}
 				continue;
 			}
 
Index: branches/PHP_5_4/main/php_version.h
===================================================================
--- branches/PHP_5_4/main/php_version.h	(revision 321767)
+++ branches/PHP_5_4/main/php_version.h	(working copy)
@@ -3,6 +3,6 @@
 #define PHP_MAJOR_VERSION 5
 #define PHP_MINOR_VERSION 4
 #define PHP_RELEASE_VERSION 0
-#define PHP_EXTRA_VERSION "RC5-dev"
-#define PHP_VERSION "5.4.0RC5-dev"
+#define PHP_EXTRA_VERSION "RC2-dev"
+#define PHP_VERSION "5.4.0RC2-dev"
 #define PHP_VERSION_ID 50400
Index: branches/PHP_5_4/main/php_variables.c
===================================================================
--- branches/PHP_5_4/main/php_variables.c	(revision 321767)
+++ branches/PHP_5_4/main/php_variables.c	(working copy)
@@ -178,15 +178,10 @@
 			} else {
 				escaped_index = index;
 				if (zend_symtable_find(symtable1, escaped_index, index_len + 1, (void **) &gpc_element_p) == FAILURE
-					|| Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
-					if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
-						if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
-							php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
-						}
-						MAKE_STD_ZVAL(gpc_element);
-						array_init(gpc_element);
-						zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
-					}
+						|| Z_TYPE_PP(gpc_element_p) != IS_ARRAY) {
+					MAKE_STD_ZVAL(gpc_element);
+					array_init(gpc_element);
+					zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
 				}
 				if (index != escaped_index) {
 					efree(escaped_index);
@@ -225,14 +220,7 @@
 				zend_symtable_exists(symtable1, escaped_index, index_len + 1)) {
 				zval_ptr_dtor(&gpc_element);
 			} else {
-				if (zend_hash_num_elements(symtable1) <= PG(max_input_vars)) {
-					if (zend_hash_num_elements(symtable1) == PG(max_input_vars)) {
-						php_error_docref(NULL TSRMLS_CC, E_WARNING, "Input variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
-					}
-					zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
-				} else {
-					zval_ptr_dtor(&gpc_element);
-				}
+				zend_symtable_update(symtable1, escaped_index, index_len + 1, &gpc_element, sizeof(zval *), (void **) &gpc_element_p);
 			}
 			if (escaped_index != index) {
 				efree(escaped_index);
@@ -246,6 +234,7 @@
 {
 	char *var, *val, *e, *s, *p;
 	zval *array_ptr = (zval *) arg;
+	long num_vars = 0;
 
 	if (SG(request_info).post_data == NULL) {
 		return;
@@ -270,6 +259,11 @@
 			}
 			efree(val);
 		}
+		++num_vars;
+		if (PG(max_input_vars) && num_vars >= PG(max_input_vars)) {
+			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Post variables exceeded %ld. To increase the limit change max_input_vars in php.ini.", PG(max_input_vars));
+			return;
+		}
 		s = p + 1;
 	}
 	if (s < e) {
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Oct 31 23:01:28 2024 UTC