com php-src: Fixed bug #66608 (Incorrect behavior with nested "finally" blocks): NEWS Zend/tests/bug66608.phpt Zend/zend_compile.h Zend/zend_opcode.c
Zend/zend_vm_def.h Zend/zen d_vm_execute.h
| From: | Xinchen Hui | Date: | Fri, 18 Jul 2014 07:45:31 +0000 |
| Subject: | com php-src: Fixed bug #66608 (Incorrect behavior with nested "finally" blocks): NEWS Zend/tests/bug66608.phpt Zend/zend_compile.h Zend/zend_opcode.c Zend/zend_vm_def.h Zend/zen d_vm_execute.h |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-79501@lists.php.net to get a copy of this message | ||
Commit: de433d4c4756e18515e4b394298f9e3e60009692
Author: Xinchen Hui <laruence@php.net> Fri, 18 Jul 2014 15:45:31 +0800
Parents: 7446c81aed7d085f05dae0d785c7f49109bc44ec
Branches: PHP-5.5 PHP-5.6 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=de433d4c4756e18515e4b394298f9e3e60009692
Log:
Fixed bug #66608 (Incorrect behavior with nested "finally" blocks)
Bugs:
https://bugs.php.net/66608
Changed paths:
M NEWS
A 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/NEWS b/NEWS
index cea0051..44c09d0 100644
--- a/NEWS
+++ b/NEWS
@@ -17,6 +17,8 @@ PHP NEWS
. Fixed bug #67151 (strtr with empty array crashes). (Nikita)
. Fixed bug #67407 (Windows 8.1/Server 2012 R2 reported as Windows 8/Server
2012). (Christian Wenz)
+ . Fixed bug #66608 (Incorrect behavior with nested "finally" blocks).
+ (Laruence, Dmitry)
. Implemented FR #34407 (ucwords and Title Case). (Tjerk)
- CLI server:
diff --git a/Zend/tests/bug66608.phpt b/Zend/tests/bug66608.phpt
new file mode 100644
index 0000000..6329506
--- /dev/null
+++ b/Zend/tests/bug66608.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Bug #66608 (Incorrect behavior with nested "finally" blocks)
+--FILE--
+<?php
+function bar() {
+ try {
+ echo "1\n";
+ } finally {
+ try {
+ throw new Exception ("");
+ } catch (Exception $ab) {
+ echo "2\n";
+ } finally {
+ try {
+ } finally {
+ echo "3\n";
+ try {
+ } finally {
+ }
+ echo "4\n";
+ }
+ }
+ echo "5\n";
+ try {
+ } finally {
+ echo "6\n";
+ }
+ }
+ echo "7\n";
+}
+bar();
+--EXPECT--
+1
+2
+3
+4
+5
+6
+7
diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h
index 2a3d58e..e6e30f3 100644
--- a/Zend/zend_compile.h
+++ b/Zend/zend_compile.h
@@ -843,6 +843,9 @@ 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
+
END_EXTERN_C()
#define ZEND_CLONE_FUNC_NAME "__clone"
diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c
index 025e8fa..cd810ec 100644
--- a/Zend/zend_opcode.c
+++ b/Zend/zend_opcode.c
@@ -538,7 +538,7 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
SET_UNUSED(opline->op2);
opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
if (op_array->try_catch_array[i].catch_op) {
- opline->extended_value = 1;
+ opline->extended_value = ZEND_FAST_CALL_FOR_CATCH;
opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
}
@@ -603,6 +603,26 @@ 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;
@@ -644,6 +664,9 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
case ZEND_JMP:
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);
+ break;
case ZEND_FAST_RET:
zend_resolve_finally_ret(op_array, i TSRMLS_CC);
break;
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index f76e529..161dd77 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -5396,13 +5396,13 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
{
USE_OPLINE
- if (opline->extended_value &&
+ if ((opline->extended_value & ZEND_FAST_CALL_FOR_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]);
ZEND_VM_CONTINUE();
}
- EX(fast_ret) = opline + 1;
+ EX(fast_ret) = opline;
ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
ZEND_VM_CONTINUE();
}
@@ -5410,7 +5410,10 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
{
if (EX(fast_ret)) {
- ZEND_VM_SET_OPCODE(EX(fast_ret));
+ ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
+ if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
+ EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
+ }
ZEND_VM_CONTINUE();
} else {
/* special case for unhandled exceptions */
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 94026a0..c94c2d7 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1137,13 +1137,13 @@ static int ZEND_FASTCALL
ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
- if (opline->extended_value &&
+ if ((opline->extended_value & ZEND_FAST_CALL_FOR_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]);
ZEND_VM_CONTINUE();
}
- EX(fast_ret) = opline + 1;
+ EX(fast_ret) = opline;
ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
ZEND_VM_CONTINUE();
}
@@ -1151,7 +1151,10 @@ static int ZEND_FASTCALL
ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
if (EX(fast_ret)) {
- ZEND_VM_SET_OPCODE(EX(fast_ret));
+ ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
+ if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
+ EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
+ }
ZEND_VM_CONTINUE();
} else {
/* special case for unhandled exceptions */