dmitry                                   Wed, 25 Aug 2010 09:14:36 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=302764

Log:
Fixed bug #52614 (Memory leak when writing on uninitialized variable returned 
from method call)

Bug: http://bugs.php.net/52614 (Assigned) Memory leak when writing on 
uninitialized variable returned from method call
      
Changed paths:
    U   php/php-src/trunk/NEWS
    A   php/php-src/trunk/Zend/tests/bug52614.phpt
    U   php/php-src/trunk/Zend/zend_compile.c
    U   php/php-src/trunk/Zend/zend_language_parser.y
    U   php/php-src/trunk/Zend/zend_vm_def.h
    U   php/php-src/trunk/Zend/zend_vm_execute.h
    U   php/php-src/trunk/Zend/zend_vm_opcodes.h

Modified: php/php-src/trunk/NEWS
===================================================================
--- php/php-src/trunk/NEWS	2010-08-25 08:26:12 UTC (rev 302763)
+++ php/php-src/trunk/NEWS	2010-08-25 09:14:36 UTC (rev 302764)
@@ -117,6 +117,8 @@
 - Fixed a NULL pointer dereference when processing invalid XML-RPC
   requests (Fixes CVE-2010-0397, bug #51288). (Raphael Geissert)

+- Fixed bug #52614 (Memory leak when writing on uninitialized variable returned
+  from method call). (Dmitry)
 - Fixed bug #51338 (URL-Rewriter is still enabled if use_only_cookies is
   on). (Ilia, j dot jeising at gmail dot com)
 - Fixed bug #51269 (zlib.output_compression Overwrites Vary Header). (Adam)

Added: php/php-src/trunk/Zend/tests/bug52614.phpt
===================================================================
--- php/php-src/trunk/Zend/tests/bug52614.phpt	                        (rev 0)
+++ php/php-src/trunk/Zend/tests/bug52614.phpt	2010-08-25 09:14:36 UTC (rev 302764)
@@ -0,0 +1,83 @@
+--TEST--
+Bug #52614 (Memory leak when writing on uninitialized variable returned from method call)
+--FILE--
+<?php
+class foo {
+	public $a1;
+	public $a2 = array();
+	public $a3;
+	public $o1;
+	public $o2;
+
+	public function f1() {
+		return $this->a1;
+	}
+
+	public function f2() {
+		return $this->a2;
+	}
+
+	public function f3() {
+		$this->a3 = array();
+		return $this->a3;
+	}
+
+	public function f4() {
+		return $this->o1;
+	}
+
+	public function f5() {
+		$this->o2 = new stdClass;
+		return $this->o2;
+	}
+
+	public function &f6() {
+		return $this->a1;
+	}
+
+	public function f7(&$x) {
+		$x = 2;
+	}
+
+}
+
+$foo = new foo;
+
+$foo->f1()[0] = 1;
+var_dump($foo->a1);
+
+$foo->f2()[0] = 1;
+var_dump($foo->a2);
+
+$foo->f3()[0] = 1;
+var_dump($foo->a3);
+
+$foo->f4()->a = 1;
+var_dump($foo->o1);
+
+$foo->f5()->a = 1;
+var_dump($foo->o2);
+
+$foo->a1[0] = 1;
+$foo->f7($foo->f6()[0]);
+var_dump($foo->a1[0]);
+$foo->f1()[0]++;
+var_dump($foo->a1[0]);
+$foo->f6()[0]++;
+var_dump($foo->a1[0]);
+--EXPECTF--
+NULL
+array(0) {
+}
+array(0) {
+}
+
+Strict Standards: Creating default object from empty value in %sbug52614.php on line 52
+NULL
+object(stdClass)#%d (1) {
+  ["a"]=>
+  int(1)
+}
+int(2)
+int(2)
+int(3)

Modified: php/php-src/trunk/Zend/zend_compile.c
===================================================================
--- php/php-src/trunk/Zend/zend_compile.c	2010-08-25 08:26:12 UTC (rev 302763)
+++ php/php-src/trunk/Zend/zend_compile.c	2010-08-25 09:14:36 UTC (rev 302764)
@@ -550,6 +550,14 @@
 		op.constant = zend_add_literal(CG(active_op_array), &_c); \
 	} while (0)

+static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */
+{
+	zend_uint type = variable->EA;
+
+	return  ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL));
+}
+/* }}} */
+
 void zend_do_binary_op(zend_uchar op, znode *result, const znode *op1, const znode *op2 TSRMLS_DC) /* {{{ */
 {
 	zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC);
@@ -781,6 +789,18 @@
 	zend_op opline;
 	zend_llist *fetch_list_ptr;

+	zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
+
+	if (zend_is_function_or_method_call(parent)) {
+		init_op(&opline TSRMLS_CC);
+		opline.opcode = ZEND_SEPARATE;
+		SET_NODE(opline.op1, parent);
+		SET_UNUSED(opline.op2);
+		opline.result_type = IS_VAR;
+		opline.result.var = opline.op1.var;
+		zend_llist_add_element(fetch_list_ptr, &opline);
+	}
+
 	init_op(&opline TSRMLS_CC);
 	opline.opcode = ZEND_FETCH_DIM_W;	/* the backpatching routine assumes W */
 	opline.result_type = IS_VAR;
@@ -802,7 +822,6 @@

 	GET_NODE(result, opline.result);

-	zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr);
 	zend_llist_add_element(fetch_list_ptr, &opline);
 }
 /* }}} */
@@ -985,14 +1004,6 @@
 }
 /* }}} */

-static inline zend_bool zend_is_function_or_method_call(const znode *variable) /* {{{ */
-{
-	zend_uint type = variable->EA;
-
-	return  ((type & ZEND_PARSED_METHOD_CALL) || (type == ZEND_PARSED_FUNCTION_CALL));
-}
-/* }}} */
-
 void zend_do_assign_ref(znode *result, const znode *lvar, const znode *rvar TSRMLS_DC) /* {{{ */
 {
 	zend_op *opline;
@@ -1307,6 +1318,14 @@

 		while (le) {
 			opline_ptr = (zend_op *)le->data;
+			if (opline_ptr->opcode == ZEND_SEPARATE) {
+				if (type != BP_VAR_R && type != BP_VAR_IS) {
+					opline = get_next_op(CG(active_op_array) TSRMLS_CC);
+					memcpy(opline, opline_ptr, sizeof(zend_op));
+				}
+				le = le->next;
+				continue;
+			}
 			opline = get_next_op(CG(active_op_array) TSRMLS_CC);
 			memcpy(opline, opline_ptr, sizeof(zend_op));
 			if (opline->op1_type == IS_VAR &&
@@ -4865,6 +4884,16 @@
 		}
 	}

+	if (zend_is_function_or_method_call(object)) {
+		init_op(&opline TSRMLS_CC);
+		opline.opcode = ZEND_SEPARATE;
+		SET_NODE(opline.op1, object);
+		SET_UNUSED(opline.op2);
+		opline.result_type = IS_VAR;
+		opline.result.var = opline.op1.var;
+		zend_llist_add_element(fetch_list_ptr, &opline);
+	}
+
 	init_op(&opline TSRMLS_CC);
 	opline.opcode = ZEND_FETCH_OBJ_W;	/* the backpatching routine assumes W */
 	opline.result_type = IS_VAR;
@@ -5745,7 +5774,11 @@
 			if (fetch->opcode == ZEND_FETCH_DIM_W && fetch->op2_type == IS_UNUSED) {
 				zend_error(E_COMPILE_ERROR, "Cannot use [] for reading");
 			}
-			fetch->opcode -= 3; /* FETCH_W -> FETCH_R */
+			if (fetch->opcode == ZEND_SEPARATE) {
+				MAKE_NOP(fetch);
+			} else {
+				fetch->opcode -= 3; /* FETCH_W -> FETCH_R */
+			}
 		}
 		/* prevent double SWITCH_FREE */
 		zend_stack_top(&CG(foreach_copy_stack), (void **) &foreach_copy);

Modified: php/php-src/trunk/Zend/zend_language_parser.y
===================================================================
--- php/php-src/trunk/Zend/zend_language_parser.y	2010-08-25 08:26:12 UTC (rev 302763)
+++ php/php-src/trunk/Zend/zend_language_parser.y	2010-08-25 09:14:36 UTC (rev 302764)
@@ -932,7 +932,7 @@

 array_method_dereference:
 		array_method_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
-	|	method '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
+	|	method '[' dim_offset ']' { $1.EA = ZEND_PARSED_METHOD_CALL; fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
 ;

 method:
@@ -942,7 +942,7 @@
 ;

 method_or_not:
-		method						{ $$ = $1; zend_do_push_object(&$$ TSRMLS_CC); $$.EA = ZEND_PARSED_METHOD_CALL; }
+		method						{ $$ = $1; $$.EA = ZEND_PARSED_METHOD_CALL; zend_do_push_object(&$$ TSRMLS_CC); }
 	|	array_method_dereference	{ $$ = $1; zend_do_push_object(&$$ TSRMLS_CC); }
 	|	/* empty */ { $$.EA = ZEND_PARSED_MEMBER; }
 ;
@@ -964,7 +964,7 @@

 array_function_dereference:
 		array_function_dereference '[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$3 TSRMLS_CC); }
-	|	function_call { zend_do_begin_variable_parse(TSRMLS_C); $$.EA = ZEND_PARSED_FUNCTION_CALL; }
+	|	function_call { zend_do_begin_variable_parse(TSRMLS_C); $1.EA = ZEND_PARSED_FUNCTION_CALL; }
 		'[' dim_offset ']' { fetch_array_dim(&$$, &$1, &$4 TSRMLS_CC); }
 ;


Modified: php/php-src/trunk/Zend/zend_vm_def.h
===================================================================
--- php/php-src/trunk/Zend/zend_vm_def.h	2010-08-25 08:26:12 UTC (rev 302763)
+++ php/php-src/trunk/Zend/zend_vm_def.h	2010-08-25 09:14:36 UTC (rev 302764)
@@ -4998,4 +4998,25 @@
 	ZEND_VM_NEXT_OPCODE();
 }

+ZEND_VM_HANDLER(156, ZEND_SEPARATE, VAR, UNUSED)
+{
+	USE_OPLINE
+	zval *var_ptr, *new_zv;
+
+	SAVE_OPLINE();
+	var_ptr = EX_T(opline->op1.var).var.ptr;
+	if (Z_TYPE_P(var_ptr) != IS_OBJECT &&
+	    !PZVAL_IS_REF(var_ptr) &&
+	    Z_REFCOUNT_P(var_ptr) > 1) {
+
+		Z_DELREF_P(var_ptr);
+		ALLOC_ZVAL(new_zv);
+		INIT_PZVAL_COPY(new_zv, var_ptr);
+		var_ptr = new_zv;
+		zval_copy_ctor(var_ptr);
+		EX_T(opline->op1.var).var.ptr = var_ptr;
+	}
+	ZEND_VM_NEXT_OPCODE();
+}
+
 ZEND_VM_EXPORT_HELPER(zend_do_fcall, zend_do_fcall_common_helper)

Modified: php/php-src/trunk/Zend/zend_vm_execute.h
===================================================================
--- php/php-src/trunk/Zend/zend_vm_execute.h	2010-08-25 08:26:12 UTC (rev 302763)
+++ php/php-src/trunk/Zend/zend_vm_execute.h	2010-08-25 09:14:36 UTC (rev 302764)
@@ -18807,6 +18807,27 @@
 	ZEND_VM_NEXT_OPCODE();
 }

+static int ZEND_FASTCALL  ZEND_SEPARATE_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
+{
+	USE_OPLINE
+	zval *var_ptr, *new_zv;
+
+	SAVE_OPLINE();
+	var_ptr = EX_T(opline->op1.var).var.ptr;
+	if (Z_TYPE_P(var_ptr) != IS_OBJECT &&
+	    !PZVAL_IS_REF(var_ptr) &&
+	    Z_REFCOUNT_P(var_ptr) > 1) {
+
+		Z_DELREF_P(var_ptr);
+		ALLOC_ZVAL(new_zv);
+		INIT_PZVAL_COPY(new_zv, var_ptr);
+		var_ptr = new_zv;
+		zval_copy_ctor(var_ptr);
+		EX_T(opline->op1.var).var.ptr = var_ptr;
+	}
+	ZEND_VM_NEXT_OPCODE();
+}
+
 static int ZEND_FASTCALL  ZEND_ADD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
 {
 	USE_OPLINE
@@ -39488,6 +39509,31 @@
   	ZEND_BIND_TRAITS_SPEC_HANDLER,
   	ZEND_BIND_TRAITS_SPEC_HANDLER,
   	ZEND_BIND_TRAITS_SPEC_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_SEPARATE_SPEC_VAR_UNUSED_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
+  	ZEND_NULL_HANDLER,
   	ZEND_NULL_HANDLER
   };
   zend_opcode_handlers = (opcode_handler_t*)labels;

Modified: php/php-src/trunk/Zend/zend_vm_opcodes.h
===================================================================
--- php/php-src/trunk/Zend/zend_vm_opcodes.h	2010-08-25 08:26:12 UTC (rev 302763)
+++ php/php-src/trunk/Zend/zend_vm_opcodes.h	2010-08-25 09:14:36 UTC (rev 302764)
@@ -156,3 +156,4 @@
 #define ZEND_DECLARE_LAMBDA_FUNCTION         153
 #define ZEND_ADD_TRAIT                       154
 #define ZEND_BIND_TRAITS                     155
+#define ZEND_SEPARATE                        156
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to