From: Xinchen Hui Date: Sat, 19 Jul 2014 09:19:01 +0000 (+0800) Subject: Improve fix for #66608 X-Git-Tag: php-5.5.16RC1~37 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8ff00e6e85669ad0a5a47421fe639b6fb6f91669;p=php Improve fix for #66608 --- diff --git a/Zend/tests/bug66608.phpt b/Zend/tests/bug66608.phpt index 6329506d06..5a499a1dab 100644 --- a/Zend/tests/bug66608.phpt +++ b/Zend/tests/bug66608.phpt @@ -5,28 +5,56 @@ Bug #66608 (Incorrect behavior with nested "finally" blocks) function bar() { try { echo "1\n"; + try { + } finally { + try { + } finally { + } + echo "2\n"; + } } finally { try { throw new Exception (""); } catch (Exception $ab) { - echo "2\n"; + echo "3\n"; } finally { try { } finally { - echo "3\n"; + echo "4\n"; try { } finally { } - echo "4\n"; + echo "5\n"; } } - echo "5\n"; + echo "6\n"; try { } finally { - echo "6\n"; + while (1) { + try { + echo "7\n"; + break; + } finally { + echo "8\n"; + } + echo "bad"; + } + echo "9\n"; + while (1) { + try { + throw new Exception(""); + } catch(Exception $e) { + echo "10\n"; + break; + } finally { + echo "11\n"; + } + echo "bak\n"; + } } + echo "12\n"; } - echo "7\n"; + echo "13\n"; } bar(); --EXPECT-- @@ -37,3 +65,9 @@ bar(); 5 6 7 +8 +9 +10 +11 +12 +13 diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index e6e30f37b7..f6b1be96fa 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -843,8 +843,8 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC); #define ZEND_FAST_RET_TO_CATCH 1 #define ZEND_FAST_RET_TO_FINALLY 2 -#define ZEND_FAST_CALL_FOR_CATCH 1 -#define ZEND_FAST_CALL_FOR_FINALLY 2 +#define ZEND_FAST_CALL_FROM_CATCH 1 +#define ZEND_FAST_CALL_FROM_FINALLY 2 END_EXTERN_C() diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index b3fb11f00f..5c032d94bd 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -509,6 +509,49 @@ static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_nu } } +static void zend_adjust_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint start, zend_uint end TSRMLS_DC) +{ + int i; + zend_uint op_num = 0; + + for (i = 0; i < op_array->last_try_catch; i++) { + if (op_array->try_catch_array[i].finally_op > start + && op_array->try_catch_array[i].finally_end < end) { + op_num = op_array->try_catch_array[i].finally_op; + start = op_array->try_catch_array[i].finally_end; + } + } + + if (op_num) { + /* Must be ZEND_FAST_CALL */ + ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL); + op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY; + op_array->opcodes[op_num - 2].op2.opline_num = fast_call; + } +} + +static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint op_num TSRMLS_DC) +{ + int i; + zend_uint finally_op_num = 0; + + for (i = 0; i < op_array->last_try_catch; i++) { + if (op_num >= op_array->try_catch_array[i].finally_op + && op_num < op_array->try_catch_array[i].finally_end) { + finally_op_num = op_array->try_catch_array[i].finally_op; + } + } + + if (finally_op_num) { + /* Must be ZEND_FAST_CALL */ + ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL); + if (op_array->opcodes[fast_call].extended_value == 0) { + op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY; + op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2; + } + } +} + static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC) { zend_uint start_op; @@ -536,11 +579,23 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, opline->opcode = ZEND_FAST_CALL; SET_UNUSED(opline->op1); SET_UNUSED(opline->op2); - opline->op1.opline_num = op_array->try_catch_array[i].finally_op; + zend_adjust_fast_call(op_array, start_op, + op_array->try_catch_array[i].finally_op, + op_array->try_catch_array[i].finally_end TSRMLS_CC); if (op_array->try_catch_array[i].catch_op) { - opline->extended_value = ZEND_FAST_CALL_FOR_CATCH; + opline->extended_value = ZEND_FAST_CALL_FROM_CATCH; opline->op2.opline_num = op_array->try_catch_array[i].catch_op; + opline->op1.opline_num = get_next_op_number(op_array); + /* generate a FAST_CALL to hole CALL_FROM_FINALLY */ + opline = get_next_op(op_array TSRMLS_CC); + opline->opcode = ZEND_FAST_CALL; + SET_UNUSED(opline->op1); + SET_UNUSED(opline->op2); + zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC); + } else { + zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC); } + opline->op1.opline_num = op_array->try_catch_array[i].finally_op; /* generate a sequence of FAST_CALL to upward finally block */ while (i > 0) { @@ -603,26 +658,6 @@ static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num T } } -static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint op_num TSRMLS_DC) -{ - int i; - zend_uint finally_op_num = 0; - - for (i = 0; i < op_array->last_try_catch; i++) { - if (op_array->try_catch_array[i].finally_op > op_num) { - break; - } - if (op_num < op_array->try_catch_array[i].finally_end) { - finally_op_num = op_array->try_catch_array[i].finally_op; - } - } - - if (finally_op_num) { - op_array->opcodes[op_num].extended_value = ZEND_FAST_CALL_FOR_FINALLY; - op_array->opcodes[op_num].op2.opline_num = finally_op_num - 2; /* it must be ZEND_FAST_CALL */ - } -} - static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC) { zend_uint i, j; @@ -666,7 +701,7 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC) zend_resolve_finally_call(op_array, i, opline->op1.opline_num TSRMLS_CC); break; case ZEND_FAST_CALL: - zend_resolve_fast_call(op_array, i TSRMLS_CC); + zend_resolve_fast_call(op_array, i, i TSRMLS_CC); break; case ZEND_FAST_RET: zend_resolve_finally_ret(op_array, i TSRMLS_CC); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 161dd77442..79453f13b3 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5396,7 +5396,7 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY) { USE_OPLINE - if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) && + if ((opline->extended_value & ZEND_FAST_CALL_FROM_CATCH) && UNEXPECTED(EG(prev_exception) != NULL)) { /* in case of unhandled exception jump to catch block instead of finally */ ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); @@ -5411,7 +5411,7 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY) { if (EX(fast_ret)) { ZEND_VM_SET_OPCODE(EX(fast_ret) + 1); - if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) { + if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) { EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num]; } ZEND_VM_CONTINUE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c94c2d755b..4d2b6f266c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1137,7 +1137,7 @@ static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) && + if ((opline->extended_value & ZEND_FAST_CALL_FROM_CATCH) && UNEXPECTED(EG(prev_exception) != NULL)) { /* in case of unhandled exception jump to catch block instead of finally */ ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]); @@ -1152,7 +1152,7 @@ static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { if (EX(fast_ret)) { ZEND_VM_SET_OPCODE(EX(fast_ret) + 1); - if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) { + if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) { EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num]; } ZEND_VM_CONTINUE();