mirror of
https://github.com/php/php-src.git
synced 2024-11-28 04:14:26 +08:00
Fixed bug #65784 (Segfault with finally).
This commit is contained in:
parent
1dfbe99ce4
commit
794a888a48
1
NEWS
1
NEWS
@ -23,6 +23,7 @@ PHP NEWS
|
||||
emalloc/efree/estrdup (Anatol, Dmitry)
|
||||
. Implemented constant scalar expressions (with support for constants)
|
||||
(RFC: https://wiki.php.net/rfc/const_scalar_exprs). (Bob)
|
||||
. Fixed bug #65784 (Segfault with finally). (Laruence, Dmitry)
|
||||
|
||||
- cURL:
|
||||
. Implemented FR #65646 (re-enable CURLOPT_FOLLOWLOCATION with open_basedir
|
||||
|
60
Zend/tests/bug65784.phpt
Normal file
60
Zend/tests/bug65784.phpt
Normal file
@ -0,0 +1,60 @@
|
||||
--TEST--
|
||||
Fixed Bug #65784 (Segfault with finally)
|
||||
--FILE--
|
||||
<?php
|
||||
function foo1() {
|
||||
try {
|
||||
throw new Exception("not catch");
|
||||
return true;
|
||||
} finally {
|
||||
try {
|
||||
throw new Exception("catched");
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
$foo = foo1();
|
||||
var_dump($foo);
|
||||
} catch (Exception $e) {
|
||||
do {
|
||||
var_dump($e->getMessage());
|
||||
} while ($e = $e->getPrevious());
|
||||
}
|
||||
|
||||
function foo2() {
|
||||
try {
|
||||
try {
|
||||
throw new Exception("catched");
|
||||
return true;
|
||||
} finally {
|
||||
try {
|
||||
throw new Exception("catched");
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
|
||||
$foo = foo2();
|
||||
var_dump($foo);
|
||||
|
||||
function foo3() {
|
||||
try {
|
||||
throw new Exception("not catched");
|
||||
return true;
|
||||
} finally {
|
||||
try {
|
||||
throw new NotExists();
|
||||
} catch (Exception $e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$bar = foo3();
|
||||
--EXPECTF--
|
||||
string(9) "not catch"
|
||||
NULL
|
||||
|
||||
Fatal error: Class 'NotExists' not found in %sbug65784.php on line %d
|
14
Zend/tests/finally_goto_001.phpt
Normal file
14
Zend/tests/finally_goto_001.phpt
Normal file
@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
jmp into a finally block 01
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
goto test;
|
||||
try {
|
||||
} finally {
|
||||
test:
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: jump into a finally block is disallowed in %sfinally_goto_001.php on line %d
|
14
Zend/tests/finally_goto_002.phpt
Normal file
14
Zend/tests/finally_goto_002.phpt
Normal file
@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
jmp into a finally block 02
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
try {
|
||||
goto test;
|
||||
} finally {
|
||||
test:
|
||||
}
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: jump into a finally block is disallowed in %sfinally_goto_002.php on line %d
|
15
Zend/tests/finally_goto_003.phpt
Normal file
15
Zend/tests/finally_goto_003.phpt
Normal file
@ -0,0 +1,15 @@
|
||||
--TEST--
|
||||
jmp into a finally block 03
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
try {
|
||||
} finally {
|
||||
goto test;
|
||||
test:
|
||||
}
|
||||
}
|
||||
echo "okey";
|
||||
?>
|
||||
--EXPECTF--
|
||||
okey
|
14
Zend/tests/finally_goto_004.phpt
Normal file
14
Zend/tests/finally_goto_004.phpt
Normal file
@ -0,0 +1,14 @@
|
||||
--TEST--
|
||||
jmp into a finally block 03
|
||||
--FILE--
|
||||
<?php
|
||||
function foo() {
|
||||
try {
|
||||
} finally {
|
||||
test:
|
||||
}
|
||||
goto test;
|
||||
}
|
||||
?>
|
||||
--EXPECTF--
|
||||
Fatal error: jump into a finally block is disallowed in %sfinally_goto_004.php on line %d
|
@ -401,6 +401,7 @@ struct _zend_execute_data {
|
||||
zend_class_entry *current_called_scope;
|
||||
zval *current_this;
|
||||
struct _zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
|
||||
zval *delayed_exception;
|
||||
call_slot *call_slots;
|
||||
call_slot *call;
|
||||
};
|
||||
|
@ -1650,6 +1650,7 @@ static zend_always_inline zend_execute_data *i_create_execute_data_from_op_array
|
||||
EX(call) = NULL;
|
||||
EG(current_execute_data) = execute_data;
|
||||
EX(nested) = nested;
|
||||
EX(delayed_exception) = NULL;
|
||||
|
||||
if (!op_array->run_time_cache && op_array->last_cache_slot) {
|
||||
op_array->run_time_cache = ecalloc(op_array->last_cache_slot, sizeof(void*));
|
||||
|
@ -489,10 +489,15 @@ static void zend_check_finally_breakout(zend_op_array *op_array, zend_uint op_nu
|
||||
zend_uint i;
|
||||
|
||||
for (i = 0; i < op_array->last_try_catch; i++) {
|
||||
if (op_array->try_catch_array[i].try_op > op_num) {
|
||||
break;
|
||||
}
|
||||
if ((op_num >= op_array->try_catch_array[i].finally_op
|
||||
if ((op_num < op_array->try_catch_array[i].finally_op ||
|
||||
op_num >= op_array->try_catch_array[i].finally_end)
|
||||
&& (dst_num >= op_array->try_catch_array[i].finally_op &&
|
||||
dst_num <= op_array->try_catch_array[i].finally_end)) {
|
||||
CG(in_compilation) = 1;
|
||||
CG(active_op_array) = op_array;
|
||||
CG(zend_lineno) = op_array->opcodes[op_num].lineno;
|
||||
zend_error(E_COMPILE_ERROR, "jump into a finally block is disallowed");
|
||||
} else if ((op_num >= op_array->try_catch_array[i].finally_op
|
||||
&& op_num <= op_array->try_catch_array[i].finally_end)
|
||||
&& (dst_num > op_array->try_catch_array[i].finally_end
|
||||
|| dst_num < op_array->try_catch_array[i].finally_op)) {
|
||||
@ -541,11 +546,11 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
|
||||
while (i > 0) {
|
||||
i--;
|
||||
if (op_array->try_catch_array[i].finally_op &&
|
||||
op_num >= op_array->try_catch_array[i].try_op &&
|
||||
op_num < op_array->try_catch_array[i].finally_op - 1 &&
|
||||
(dst_num < op_array->try_catch_array[i].try_op ||
|
||||
dst_num > op_array->try_catch_array[i].finally_end)) {
|
||||
|
||||
op_num >= op_array->try_catch_array[i].try_op &&
|
||||
op_num < op_array->try_catch_array[i].finally_op - 1 &&
|
||||
(dst_num < op_array->try_catch_array[i].try_op ||
|
||||
dst_num > op_array->try_catch_array[i].finally_end)) {
|
||||
|
||||
opline = get_next_op(op_array TSRMLS_CC);
|
||||
opline->opcode = ZEND_FAST_CALL;
|
||||
SET_UNUSED(opline->op1);
|
||||
@ -565,7 +570,7 @@ static void zend_resolve_finally_call(zend_op_array *op_array, zend_uint op_num,
|
||||
SET_UNUSED(opline->op2);
|
||||
opline->op1.opline_num = start_op;
|
||||
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5021,7 +5021,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
|
||||
{
|
||||
zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes;
|
||||
int i;
|
||||
zend_uint catch_op_num = 0, finally_op_num = 0;
|
||||
zend_uint catch_op_num = 0, finally_op_num = 0, finally_op_end = 0;
|
||||
void **stack_frame;
|
||||
|
||||
/* Figure out where the next stack frame (which maybe contains pushed
|
||||
@ -5046,6 +5046,10 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
|
||||
if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
|
||||
finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
|
||||
}
|
||||
if (op_num >= EG(active_op_array)->try_catch_array[i].finally_op &&
|
||||
op_num < EG(active_op_array)->try_catch_array[i].finally_end) {
|
||||
finally_op_end = EG(active_op_array)->try_catch_array[i].finally_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (EX(call) >= EX(call_slots)) {
|
||||
@ -5107,14 +5111,29 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
|
||||
EX(old_error_reporting) = NULL;
|
||||
|
||||
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
|
||||
zend_exception_save(TSRMLS_C);
|
||||
if (EX(delayed_exception)) {
|
||||
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
|
||||
}
|
||||
EX(delayed_exception) = EG(exception);
|
||||
EG(exception) = NULL;
|
||||
EX(fast_ret) = NULL;
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (catch_op_num) {
|
||||
if (finally_op_end && catch_op_num > finally_op_end) {
|
||||
/* we are going out of current finally scope */
|
||||
if (EX(delayed_exception)) {
|
||||
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
|
||||
EX(delayed_exception) = NULL;
|
||||
}
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else {
|
||||
if (EX(delayed_exception)) {
|
||||
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
|
||||
EX(delayed_exception) = NULL;
|
||||
}
|
||||
if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN);
|
||||
} else {
|
||||
@ -5405,10 +5424,10 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
|
||||
|
||||
ZEND_VM_HANDLER(159, ZEND_DISCARD_EXCEPTION, ANY, ANY)
|
||||
{
|
||||
if (EG(prev_exception) != NULL) {
|
||||
if (EX(delayed_exception) != NULL) {
|
||||
/* discard the previously thrown exception */
|
||||
zval_ptr_dtor(&EG(prev_exception));
|
||||
EG(prev_exception) = NULL;
|
||||
zval_ptr_dtor(&EX(delayed_exception));
|
||||
EX(delayed_exception) = NULL;
|
||||
}
|
||||
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
@ -5425,6 +5444,7 @@ ZEND_VM_HANDLER(162, ZEND_FAST_CALL, ANY, ANY)
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
EX(fast_ret) = opline + 1;
|
||||
EX(delayed_exception) = NULL;
|
||||
ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
@ -5441,16 +5461,17 @@ ZEND_VM_HANDLER(163, ZEND_FAST_RET, ANY, ANY)
|
||||
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
|
||||
zend_exception_restore(TSRMLS_C);
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
zend_exception_restore(TSRMLS_C);
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN);
|
||||
} else {
|
||||
zend_exception_restore(TSRMLS_C);
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
|
||||
EG(exception) = EX(delayed_exception);
|
||||
EX(delayed_exception) = NULL;
|
||||
if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_GENERATOR_RETURN);
|
||||
} else {
|
||||
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1016,7 +1016,7 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
|
||||
{
|
||||
zend_uint op_num = EG(opline_before_exception)-EG(active_op_array)->opcodes;
|
||||
int i;
|
||||
zend_uint catch_op_num = 0, finally_op_num = 0;
|
||||
zend_uint catch_op_num = 0, finally_op_num = 0, finally_op_end = 0;
|
||||
void **stack_frame;
|
||||
|
||||
/* Figure out where the next stack frame (which maybe contains pushed
|
||||
@ -1041,6 +1041,10 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
|
||||
if (op_num < EG(active_op_array)->try_catch_array[i].finally_op) {
|
||||
finally_op_num = EX(op_array)->try_catch_array[i].finally_op;
|
||||
}
|
||||
if (op_num >= EG(active_op_array)->try_catch_array[i].finally_op &&
|
||||
op_num < EG(active_op_array)->try_catch_array[i].finally_end) {
|
||||
finally_op_end = EG(active_op_array)->try_catch_array[i].finally_end;
|
||||
}
|
||||
}
|
||||
|
||||
if (EX(call) >= EX(call_slots)) {
|
||||
@ -1102,14 +1106,29 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
|
||||
EX(old_error_reporting) = NULL;
|
||||
|
||||
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
|
||||
zend_exception_save(TSRMLS_C);
|
||||
if (EX(delayed_exception)) {
|
||||
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
|
||||
}
|
||||
EX(delayed_exception) = EG(exception);
|
||||
EG(exception) = NULL;
|
||||
EX(fast_ret) = NULL;
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[finally_op_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (catch_op_num) {
|
||||
if (finally_op_end && catch_op_num > finally_op_end) {
|
||||
/* we are going out of current finally scope */
|
||||
if (EX(delayed_exception)) {
|
||||
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
|
||||
EX(delayed_exception) = NULL;
|
||||
}
|
||||
}
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[catch_op_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else {
|
||||
if (EX(delayed_exception)) {
|
||||
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
|
||||
EX(delayed_exception) = NULL;
|
||||
}
|
||||
if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
} else {
|
||||
@ -1159,10 +1178,10 @@ static int ZEND_FASTCALL ZEND_USER_OPCODE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS
|
||||
|
||||
static int ZEND_FASTCALL ZEND_DISCARD_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
{
|
||||
if (EG(prev_exception) != NULL) {
|
||||
if (EX(delayed_exception) != NULL) {
|
||||
/* discard the previously thrown exception */
|
||||
zval_ptr_dtor(&EG(prev_exception));
|
||||
EG(prev_exception) = NULL;
|
||||
zval_ptr_dtor(&EX(delayed_exception));
|
||||
EX(delayed_exception) = NULL;
|
||||
}
|
||||
|
||||
ZEND_VM_NEXT_OPCODE();
|
||||
@ -1179,6 +1198,7 @@ static int ZEND_FASTCALL ZEND_FAST_CALL_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
EX(fast_ret) = opline + 1;
|
||||
EX(delayed_exception) = NULL;
|
||||
ZEND_VM_SET_OPCODE(opline->op1.jmp_addr);
|
||||
ZEND_VM_CONTINUE();
|
||||
}
|
||||
@ -1195,16 +1215,17 @@ static int ZEND_FASTCALL ZEND_FAST_RET_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
|
||||
if (opline->extended_value == ZEND_FAST_RET_TO_FINALLY) {
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
|
||||
zend_exception_restore(TSRMLS_C);
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
zend_exception_restore(TSRMLS_C);
|
||||
return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
} else {
|
||||
zend_exception_restore(TSRMLS_C);
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
EG(exception) = EX(delayed_exception);
|
||||
EX(delayed_exception) = NULL;
|
||||
if (opline->extended_value == ZEND_FAST_RET_TO_CATCH) {
|
||||
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->op2.opline_num]);
|
||||
ZEND_VM_CONTINUE();
|
||||
} else if (UNEXPECTED((EX(op_array)->fn_flags & ZEND_ACC_GENERATOR) != 0)) {
|
||||
return ZEND_GENERATOR_RETURN_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
} else {
|
||||
return zend_leave_helper_SPEC(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user