]> granicus.if.org Git - php/commitdiff
Fix use-after-free of immediately invoked closure with extra args
authorNikita Popov <nikita.ppv@gmail.com>
Thu, 29 Aug 2019 10:30:39 +0000 (12:30 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Thu, 29 Aug 2019 10:32:03 +0000 (12:32 +0200)
Zend/tests/closure_extra_args.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/closure_extra_args.phpt b/Zend/tests/closure_extra_args.phpt
new file mode 100644 (file)
index 0000000..05712e0
--- /dev/null
@@ -0,0 +1,11 @@
+--TEST--
+Immediately invoked closure with extra args
+--FILE--
+<?php
+
+(function() {})(new stdClass);
+
+?>
+===DONE===
+--EXPECT--
+===DONE===
index 84a3439e3b77cc77488149047dfb33300cefbc04..df0a3d98124487f33078b37fff09e37599a918b2 100644 (file)
@@ -2398,6 +2398,11 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                        zend_clean_and_cache_symbol_table(EX(symbol_table));
                }
                EG(current_execute_data) = EX(prev_execute_data);
+
+               /* Free extra args before releasing the closure,
+                * as that may free the op_array. */
+               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+
                if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
                        zend_object *object = Z_OBJ(execute_data->This);
 #if 0
@@ -2413,7 +2418,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY)
                        OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
                }
 
-               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
                old_execute_data = execute_data;
                execute_data = EX(prev_execute_data);
                zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);
index c111f4d8933203cc0676bb49741c5f838db8ee56..28fc5dabe44d1ff1c939a2d4e05cd58117f47a1f 100644 (file)
@@ -468,6 +468,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                        zend_clean_and_cache_symbol_table(EX(symbol_table));
                }
                EG(current_execute_data) = EX(prev_execute_data);
+
+               /* Free extra args before releasing the closure,
+                * as that may free the op_array. */
+               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
+
                if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) {
                        zend_object *object = Z_OBJ(execute_data->This);
 #if 0
@@ -483,7 +488,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_
                        OBJ_RELEASE((zend_object*)execute_data->func->op_array.prototype);
                }
 
-               zend_vm_stack_free_extra_args_ex(call_info, execute_data);
                old_execute_data = execute_data;
                execute_data = EX(prev_execute_data);
                zend_vm_stack_free_call_frame_ex(call_info, old_execute_data);