Skip to content

Commit 8ff00e6

Browse files
committed
Improve fix for #66608
1 parent 9ce1a36 commit 8ff00e6

File tree

5 files changed

+104
-35
lines changed

5 files changed

+104
-35
lines changed

Zend/tests/bug66608.phpt

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,56 @@ Bug #66608 (Incorrect behavior with nested "finally" blocks)
55
function bar() {
66
try {
77
echo "1\n";
8+
try {
9+
} finally {
10+
try {
11+
} finally {
12+
}
13+
echo "2\n";
14+
}
815
} finally {
916
try {
1017
throw new Exception ("");
1118
} catch (Exception $ab) {
12-
echo "2\n";
19+
echo "3\n";
1320
} finally {
1421
try {
1522
} finally {
16-
echo "3\n";
23+
echo "4\n";
1724
try {
1825
} finally {
1926
}
20-
echo "4\n";
27+
echo "5\n";
2128
}
2229
}
23-
echo "5\n";
30+
echo "6\n";
2431
try {
2532
} finally {
26-
echo "6\n";
33+
while (1) {
34+
try {
35+
echo "7\n";
36+
break;
37+
} finally {
38+
echo "8\n";
39+
}
40+
echo "bad";
41+
}
42+
echo "9\n";
43+
while (1) {
44+
try {
45+
throw new Exception("");
46+
} catch(Exception $e) {
47+
echo "10\n";
48+
break;
49+
} finally {
50+
echo "11\n";
51+
}
52+
echo "bak\n";
53+
}
2754
}
55+
echo "12\n";
2856
}
29-
echo "7\n";
57+
echo "13\n";
3058
}
3159
bar();
3260
--EXPECT--
@@ -37,3 +65,9 @@ bar();
3765
5
3866
6
3967
7
68+
8
69+
9
70+
10
71+
11
72+
12
73+
13

Zend/zend_compile.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -843,8 +843,8 @@ int zend_add_literal(zend_op_array *op_array, const zval *zv TSRMLS_DC);
843843
#define ZEND_FAST_RET_TO_CATCH 1
844844
#define ZEND_FAST_RET_TO_FINALLY 2
845845

846-
#define ZEND_FAST_CALL_FOR_CATCH 1
847-
#define ZEND_FAST_CALL_FOR_FINALLY 2
846+
#define ZEND_FAST_CALL_FROM_CATCH 1
847+
#define ZEND_FAST_CALL_FROM_FINALLY 2
848848

849849
END_EXTERN_C()
850850

Zend/zend_opcode.c

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,49 @@ static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_nu
509509
}
510510
}
511511

512+
static void zend_adjust_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint start, zend_uint end TSRMLS_DC)
513+
{
514+
int i;
515+
zend_uint op_num = 0;
516+
517+
for (i = 0; i < op_array->last_try_catch; i++) {
518+
if (op_array->try_catch_array[i].finally_op > start
519+
&& op_array->try_catch_array[i].finally_end < end) {
520+
op_num = op_array->try_catch_array[i].finally_op;
521+
start = op_array->try_catch_array[i].finally_end;
522+
}
523+
}
524+
525+
if (op_num) {
526+
/* Must be ZEND_FAST_CALL */
527+
ZEND_ASSERT(op_array->opcodes[op_num - 2].opcode == ZEND_FAST_CALL);
528+
op_array->opcodes[op_num - 2].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
529+
op_array->opcodes[op_num - 2].op2.opline_num = fast_call;
530+
}
531+
}
532+
533+
static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint fast_call, zend_uint op_num TSRMLS_DC)
534+
{
535+
int i;
536+
zend_uint finally_op_num = 0;
537+
538+
for (i = 0; i < op_array->last_try_catch; i++) {
539+
if (op_num >= op_array->try_catch_array[i].finally_op
540+
&& op_num < op_array->try_catch_array[i].finally_end) {
541+
finally_op_num = op_array->try_catch_array[i].finally_op;
542+
}
543+
}
544+
545+
if (finally_op_num) {
546+
/* Must be ZEND_FAST_CALL */
547+
ZEND_ASSERT(op_array->opcodes[finally_op_num - 2].opcode == ZEND_FAST_CALL);
548+
if (op_array->opcodes[fast_call].extended_value == 0) {
549+
op_array->opcodes[fast_call].extended_value = ZEND_FAST_CALL_FROM_FINALLY;
550+
op_array->opcodes[fast_call].op2.opline_num = finally_op_num - 2;
551+
}
552+
}
553+
}
554+
512555
static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num, zend_uint dst_num TSRMLS_DC)
513556
{
514557
zend_uint start_op;
@@ -536,11 +579,23 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
536579
opline->opcode = ZEND_FAST_CALL;
537580
SET_UNUSED(opline->op1);
538581
SET_UNUSED(opline->op2);
539-
opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
582+
zend_adjust_fast_call(op_array, start_op,
583+
op_array->try_catch_array[i].finally_op,
584+
op_array->try_catch_array[i].finally_end TSRMLS_CC);
540585
if (op_array->try_catch_array[i].catch_op) {
541-
opline->extended_value = ZEND_FAST_CALL_FOR_CATCH;
586+
opline->extended_value = ZEND_FAST_CALL_FROM_CATCH;
542587
opline->op2.opline_num = op_array->try_catch_array[i].catch_op;
588+
opline->op1.opline_num = get_next_op_number(op_array);
589+
/* generate a FAST_CALL to hole CALL_FROM_FINALLY */
590+
opline = get_next_op(op_array TSRMLS_CC);
591+
opline->opcode = ZEND_FAST_CALL;
592+
SET_UNUSED(opline->op1);
593+
SET_UNUSED(opline->op2);
594+
zend_resolve_fast_call(op_array, start_op + 1, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
595+
} else {
596+
zend_resolve_fast_call(op_array, start_op, op_array->try_catch_array[i].finally_op - 2 TSRMLS_CC);
543597
}
598+
opline->op1.opline_num = op_array->try_catch_array[i].finally_op;
544599

545600
/* generate a sequence of FAST_CALL to upward finally block */
546601
while (i > 0) {
@@ -603,26 +658,6 @@ static void zend_resolve_finally_ret(zend_op_array *op_array, zend_uint op_num T
603658
}
604659
}
605660

606-
static void zend_resolve_fast_call(zend_op_array *op_array, zend_uint op_num TSRMLS_DC)
607-
{
608-
int i;
609-
zend_uint finally_op_num = 0;
610-
611-
for (i = 0; i < op_array->last_try_catch; i++) {
612-
if (op_array->try_catch_array[i].finally_op > op_num) {
613-
break;
614-
}
615-
if (op_num < op_array->try_catch_array[i].finally_end) {
616-
finally_op_num = op_array->try_catch_array[i].finally_op;
617-
}
618-
}
619-
620-
if (finally_op_num) {
621-
op_array->opcodes[op_num].extended_value = ZEND_FAST_CALL_FOR_FINALLY;
622-
op_array->opcodes[op_num].op2.opline_num = finally_op_num - 2; /* it must be ZEND_FAST_CALL */
623-
}
624-
}
625-
626661
static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
627662
{
628663
zend_uint i, j;
@@ -666,7 +701,7 @@ static void zend_resolve_finally_calls(zend_op_array *op_array TSRMLS_DC)
666701
zend_resolve_finally_call(op_array, i, opline->op1.opline_num TSRMLS_CC);
667702
break;
668703
case ZEND_FAST_CALL:
669-
zend_resolve_fast_call(op_array, i TSRMLS_CC);
704+
zend_resolve_fast_call(op_array, i, i TSRMLS_CC);
670705
break;
671706
case ZEND_FAST_RET:
672707
zend_resolve_finally_ret(op_array, i TSRMLS_CC);

Zend/zend_vm_def.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5396,7 +5396,7 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
53965396
{
53975397
USE_OPLINE
53985398

5399-
if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) &&
5399+
if ((opline->extended_value & ZEND_FAST_CALL_FROM_CATCH) &&
54005400
UNEXPECTED(EG(prev_exception) != NULL)) {
54015401
/* in case of unhandled exception jump to catch block instead of finally */
54025402
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)
54115411
{
54125412
if (EX(fast_ret)) {
54135413
ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
5414-
if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
5414+
if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) {
54155415
EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
54165416
}
54175417
ZEND_VM_CONTINUE();

Zend/zend_vm_execute.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
11371137
{
11381138
USE_OPLINE
11391139

1140-
if ((opline->extended_value & ZEND_FAST_CALL_FOR_CATCH) &&
1140+
if ((opline->extended_value & ZEND_FAST_CALL_FROM_CATCH) &&
11411141
UNEXPECTED(EG(prev_exception) != NULL)) {
11421142
/* in case of unhandled exception jump to catch block instead of finally */
11431143
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)
11521152
{
11531153
if (EX(fast_ret)) {
11541154
ZEND_VM_SET_OPCODE(EX(fast_ret) + 1);
1155-
if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FOR_FINALLY)) {
1155+
if ((EX(fast_ret)->extended_value & ZEND_FAST_CALL_FROM_FINALLY)) {
11561156
EX(fast_ret) = &EX(op_array)->opcodes[EX(fast_ret)->op2.opline_num];
11571157
}
11581158
ZEND_VM_CONTINUE();

0 commit comments

Comments
 (0)