com php-src: Improve fix for #66608: Zend/tests/bug66608.phpt Zend/zend_compile.h Zend/zend_opcode.c Zend/zend_ vm_def.h Zend/zend_vm_execute.h
| From: | Xinchen Hui | Date: | Sat, 19 Jul 2014 09:19:01 +0000 |
| Subject: | com php-src: Improve fix for #66608: Zend/tests/bug66608.phpt Zend/zend_compile.h Zend/zend_opcode.c Zend/zend_ vm_def.h Zend/zend_vm_execute.h | ||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-79525@lists.php.net to get a copy of this message | ||
Commit: 8ff00e6e85669ad0a5a47421fe639b6fb6f91669
Author: Xinchen Hui <laruence@php.net> Sat, 19 Jul 2014 17:19:01 +0800
Parents: 9ce1a36af2295a75e4244eac3085f82d0c25105d
Branches: PHP-5.5 PHP-5.6 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=8ff00e6e85669ad0a5a47421fe639b6fb6f91669
Log:
Improve fix for #66608
Bugs:
https://bugs.php.net/66608
Changed paths:
M Zend/tests/bug66608.phpt
M Zend/zend_compile.h
M Zend/zend_opcode.c
M Zend/zend_vm_def.h
M Zend/zend_vm_execute.h
Diff:
diff --git a/Zend/tests/bug66608.phpt b/Zend/tests/bug66608.phpt
index 6329506..5a499a1 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 e6e30f3..f6b1be9 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 b3fb11f..5c032d9 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 161dd77..79453f1 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 c94c2d7..4d2b6f2 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();