]> granicus.if.org Git - php/commitdiff
fix crash when unexpectedly passed by-ref parameter is modified
authorStanislav Malyshev <stas@php.net>
Tue, 18 Aug 2009 20:51:49 +0000 (20:51 +0000)
committerStanislav Malyshev <stas@php.net>
Tue, 18 Aug 2009 20:51:49 +0000 (20:51 +0000)
Zend/tests/unexpected_ref_bug.phpt [new file with mode: 0755]
Zend/zend_execute_API.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/standard/tests/array/unexpected_array_mod_bug.phpt [new file with mode: 0755]

diff --git a/Zend/tests/unexpected_ref_bug.phpt b/Zend/tests/unexpected_ref_bug.phpt
new file mode 100755 (executable)
index 0000000..61fe1aa
--- /dev/null
@@ -0,0 +1,18 @@
+--TEST--
+Crash when function parameter modified via unexpected reference
+--FILE--
+<?php
+function my_errorhandler($errno,$errormsg) {
+  global $my_var;
+  $my_var = 0;
+  return true;
+}
+set_error_handler("my_errorhandler");
+$my_var = str_repeat("A",64);
+$data = call_user_func_array("explode",array(new StdClass(), &$my_var));
+$my_var=array(1,2,3);
+$data = call_user_func_array("implode",array(&$my_var, new StdClass()));
+echo "Done.\n";
+?>
+--EXPECTF--
+Done.
index 434f1e08f9aedf192be8fd38baad05780550c0d7..0e64a41c1ca0d36f8fbf6a771eb97e2cff82d502 100644 (file)
@@ -921,6 +921,12 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TS
        for (i=0; i<fci->param_count; i++) {
                zval *param;
 
+               if(EX(function_state).function->type == ZEND_INTERNAL_FUNCTION
+                       && !ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i + 1)
+                       && PZVAL_IS_REF(*fci->params[i])) {
+                       SEPARATE_ZVAL(fci->params[i]);
+               }
+
                if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i+1)
                        && !PZVAL_IS_REF(*fci->params[i])) {
                        if ((*fci->params[i])->refcount>1) {
index bc38c31447b4968067d638fb53e63dafa7c9b8cb..33b94e1849a8c684760f4c7f44900fccbe29241d 100644 (file)
@@ -2371,6 +2371,10 @@ ZEND_VM_HANDLER(67, ZEND_SEND_REF, VAR|CV, ANY)
                zend_error_noreturn(E_ERROR, "Only variables can be passed by reference");
        }
 
+       if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) {
+               ZEND_VM_DISPATCH_TO_HELPER(zend_send_by_var_helper);
+        }
+
        SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr);
        varptr = *varptr_ptr;
        varptr->refcount++;
index 5d431eadb1a4df2aafac4f829b68a0895d39050c..f348b31d914c1b3ad6b502440e7a687e8aa9ec81 100644 (file)
@@ -7584,6 +7584,10 @@ static int ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Only variables can be passed by reference");
        }
 
+       if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) {
+               return zend_send_by_var_helper_SPEC_VAR(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+        }
+
        SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr);
        varptr = *varptr_ptr;
        varptr->refcount++;
@@ -20009,6 +20013,10 @@ static int ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                zend_error_noreturn(E_ERROR, "Only variables can be passed by reference");
        }
 
+       if (EX(function_state).function->type == ZEND_INTERNAL_FUNCTION && !ARG_SHOULD_BE_SENT_BY_REF(EX(fbc), opline->op2.u.opline_num)) {
+               return zend_send_by_var_helper_SPEC_CV(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
+        }
+
        SEPARATE_ZVAL_TO_MAKE_IS_REF(varptr_ptr);
        varptr = *varptr_ptr;
        varptr->refcount++;
diff --git a/ext/standard/tests/array/unexpected_array_mod_bug.phpt b/ext/standard/tests/array/unexpected_array_mod_bug.phpt
new file mode 100755 (executable)
index 0000000..58f2249
--- /dev/null
@@ -0,0 +1,21 @@
+--TEST--
+Crash when function parameter modified via reference
+--FILE--
+<?php
+function usercompare($a,$b) {
+  unset($GLOBALS['my_var'][2]); 
+  return 0;
+}
+$my_var = array(1 => "entry_1",
+2 => "entry_2",
+3 => "entry_3",
+4 => "entry_4",
+5 => "entry_5");
+usort($my_var, "usercompare");
+
+echo "Done.\n";
+?>
+--EXPECTF--
+
+Warning: usort(): Array was modified by the user comparison function in %s on line %d
+Done.