diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 79c0e6133c69f..41c1a3a2c27fa 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -3446,9 +3446,9 @@ ZEND_API void zend_free_compiled_variables(zend_execute_data *execute_data) /* { } /* }}} */ -#define ZEND_VM_INTERRUPT_CHECK() do { \ +#define ZEND_VM_INTERRUPT_CHECK(target_opline) do { \ if (UNEXPECTED(EG(vm_interrupt))) { \ - ZEND_VM_INTERRUPT(); \ + ZEND_VM_INTERRUPT(target_opline); \ } \ } while (0) @@ -4677,8 +4677,8 @@ static zend_always_inline zend_execute_data *_zend_vm_stack_push_call_frame(uint #define ZEND_VM_SET_OPCODE(new_op) \ CHECK_SYMBOL_TABLES() \ - OPLINE = new_op; \ - ZEND_VM_INTERRUPT_CHECK() + ZEND_VM_INTERRUPT_CHECK(new_op); \ + OPLINE = new_op #define ZEND_VM_SET_RELATIVE_OPCODE(opline, offset) \ ZEND_VM_SET_OPCODE(ZEND_OFFSET_TO_OPLINE(opline, offset)) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 786a8f2db4b9b..6fc0edd092a8f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -9672,15 +9672,20 @@ ZEND_VM_HOT_TYPE_SPEC_HANDLER(ZEND_FE_FETCH_R, op->op2_type == IS_CV && (op1_inf ZEND_VM_DEFINE_OP(137, ZEND_OP_DATA); -ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY) +ZEND_VM_HELPER(zend_interrupt_helper, ANY, ANY, const zend_op *target_opline) { + USE_OPLINE EG(vm_interrupt) = 0; SAVE_OPLINE(); if (EG(timed_out)) { zend_timeout(); } else if (zend_interrupt_function) { zend_interrupt_function(execute_data); - ZEND_VM_ENTER(); + if (EG(current_execute_data) != execute_data || execute_data->opline != opline) { + ZEND_VM_ENTER(); + } } + + OPLINE = target_opline; ZEND_VM_CONTINUE(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 90551512ef4d2..320d47569bedf 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -413,7 +413,7 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H #define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE() #define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_LEAVE() #if defined(ZEND_VM_FP_GLOBAL_REG) -# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE() +# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(OPLINE); ZEND_VM_CONTINUE() # define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX() # define ZEND_VM_LEAVE() ZEND_VM_CONTINUE() #elif defined(ZEND_VM_IP_GLOBAL_REG) @@ -425,11 +425,11 @@ typedef ZEND_OPCODE_HANDLER_RET (ZEND_FASTCALL *opcode_handler_t) (ZEND_OPCODE_H # define ZEND_VM_ENTER() return 1 # define ZEND_VM_LEAVE() return 2 #endif -#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); -#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); +#define ZEND_VM_INTERRUPT(target) ZEND_VM_TAIL_CALL(zend_interrupt_helper_SPEC(target ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC)); +#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper_SPEC(OPLINE ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC); #define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler_func(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU)); -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS); +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(const zend_op *target_opline ZEND_OPCODE_HANDLER_ARGS_DC); static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS); static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_add_helper_SPEC(zval *op_1, zval *op_2 ZEND_OPCODE_HANDLER_ARGS_DC) @@ -3376,16 +3376,21 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_FORWARD_SPEC_H ZEND_VM_CONTINUE(); } -static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS) +static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper_SPEC(const zend_op *target_opline ZEND_OPCODE_HANDLER_ARGS_DC) { + USE_OPLINE EG(vm_interrupt) = 0; SAVE_OPLINE(); if (EG(timed_out)) { zend_timeout(); } else if (zend_interrupt_function) { zend_interrupt_function(execute_data); - ZEND_VM_ENTER(); + if (EG(current_execute_data) != execute_data || execute_data->opline != opline) { + ZEND_VM_ENTER(); + } } + + OPLINE = target_opline; ZEND_VM_CONTINUE(); } static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_FCALL_BY_NAME_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) diff --git a/Zend/zend_vm_gen.php b/Zend/zend_vm_gen.php index a8bcf96ef2d61..1ea705a1fe450 100755 --- a/Zend/zend_vm_gen.php +++ b/Zend/zend_vm_gen.php @@ -1941,7 +1941,7 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define HANDLE_EXCEPTION() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_CONTINUE()\n"); out($f,"#define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#if defined(ZEND_VM_FP_GLOBAL_REG)\n"); - out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"# define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(OPLINE); ZEND_VM_CONTINUE()\n"); out($f,"# define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"# define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); out($f,"#elif defined(ZEND_VM_IP_GLOBAL_REG)\n"); @@ -1953,15 +1953,15 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"# define ZEND_VM_ENTER() return 1\n"); out($f,"# define ZEND_VM_LEAVE() return 2\n"); out($f,"#endif\n"); - out($f,"#define ZEND_VM_INTERRUPT() ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); - out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);\n"); + out($f,"#define ZEND_VM_INTERRUPT(target) ZEND_VM_TAIL_CALL(zend_interrupt_helper".($spec?"_SPEC":"")."(target ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC));\n"); + out($f,"#define ZEND_VM_LOOP_INTERRUPT() zend_interrupt_helper".($spec?"_SPEC":"")."(OPLINE ZEND_OPCODE_HANDLER_ARGS_PASSTHRU_CC);\n"); if ($kind == ZEND_VM_KIND_HYBRID) { out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler_func(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); } else { out($f,"#define ZEND_VM_DISPATCH(opcode, opline) ZEND_VM_TAIL_CALL(((opcode_handler_t)zend_vm_get_opcode_handler(opcode, opline))(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU));\n"); } out($f,"\n"); - out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper".($spec?"_SPEC":"")."(ZEND_OPCODE_HANDLER_ARGS);\n"); + out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_interrupt_helper".($spec?"_SPEC":"")."(const zend_op *target_opline ZEND_OPCODE_HANDLER_ARGS_DC);\n"); out($f,"static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_NULL_HANDLER(ZEND_OPCODE_HANDLER_ARGS);\n"); out($f,"\n"); break; @@ -1983,11 +1983,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) out($f,"#define HANDLE_EXCEPTION_LEAVE() ZEND_ASSERT(EG(exception)); LOAD_OPLINE(); ZEND_VM_LEAVE()\n"); out($f,"#define ZEND_VM_CONTINUE() goto zend_vm_continue\n"); out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(OPLINE); ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); - out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); - out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_INTERRUPT(target) target_opline = target; goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_LOOP_INTERRUPT() target_opline = OPLINE; goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); out($f,"#define ZEND_VM_DISPATCH(opcode, opline) dispatch_handler = zend_vm_get_opcode_handler(opcode, opline); goto zend_vm_dispatch;\n"); out($f,"\n"); break; @@ -2014,11 +2014,11 @@ function gen_executor($f, $skl, $spec, $kind, $executor_name, $initializer_name) } out($f,"#define ZEND_VM_CONTINUE() goto *(void**)(OPLINE->handler)\n"); out($f,"#define ZEND_VM_RETURN() return\n"); - out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(); ZEND_VM_CONTINUE()\n"); + out($f,"#define ZEND_VM_ENTER_EX() ZEND_VM_INTERRUPT_CHECK(OPLINE); ZEND_VM_CONTINUE()\n"); out($f,"#define ZEND_VM_ENTER() execute_data = EG(current_execute_data); LOAD_OPLINE(); ZEND_VM_ENTER_EX()\n"); out($f,"#define ZEND_VM_LEAVE() ZEND_VM_CONTINUE()\n"); - out($f,"#define ZEND_VM_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); - out($f,"#define ZEND_VM_LOOP_INTERRUPT() goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_INTERRUPT(target) target_opline = target; goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); + out($f,"#define ZEND_VM_LOOP_INTERRUPT() target_opline = OPLINE; goto zend_interrupt_helper".($spec?"_SPEC":"").";\n"); out($f,"#define ZEND_VM_DISPATCH(opcode, opline) goto *(void**)(zend_vm_get_opcode_handler(opcode, opline));\n"); out($f,"\n"); break; diff --git a/ext/pcntl/tests/async_signals.phpt b/ext/pcntl/tests/async_signals.phpt index 1b27bfdb6c1c1..71534181d736b 100644 --- a/ext/pcntl/tests/async_signals.phpt +++ b/ext/pcntl/tests/async_signals.phpt @@ -18,8 +18,19 @@ posix_kill(posix_getpid(), SIGTERM); $i = 0; // dummy echo "Done!\n"; +// Test exception from signal handler (bug #81577) +pcntl_signal(SIGTERM, function ($signo) { throw new Exception("Signal"); }); +posix_kill(posix_getpid(), SIGTERM); +!$i; + ?> ---EXPECT-- +--EXPECTF-- Start! Signal handler called! Done! + +Fatal error: Uncaught Exception: Signal in %s:%d +Stack trace: +#0 %s(%d): {closure}(%s) +#1 {main} + thrown in %s on line %d