Reimplemented silence operator (@) handling on exceptions. Now each silence region is stored in op_array->brk_cont_array. On exception ZEND_HANDLE_EXCEPTION handler traverse this array and restore original EG(error_reporting) if exception occured inside a "silence" region.

This commit is contained in:
Dmitry Stogov 2014-11-26 22:44:58 +03:00
parent d1c83ef6a4
commit 303d73ecd2
6 changed files with 27 additions and 42 deletions

View File

@ -5524,13 +5524,11 @@ void zend_compile_silence(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
{
zend_ast *expr_ast = ast->child[0];
znode silence_node;
uint32_t opline_num;
zend_op *begin_silence, *end_silence;
uint32_t begin_opline_num, end_opline_num;
zend_brk_cont_element *brk_cont_element;
opline_num = get_next_op_number(CG(active_op_array));
begin_silence = zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL TSRMLS_CC);
/* pair BEGIN_SILENCE and END_SILENCE opcodes */
begin_silence->op2.num = opline_num;
begin_opline_num = get_next_op_number(CG(active_op_array));
zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL TSRMLS_CC);
if (expr_ast->kind == ZEND_AST_VAR) {
/* For @$var we need to force a FETCH instruction, otherwise the CV access will
@ -5540,9 +5538,15 @@ void zend_compile_silence(znode *result, zend_ast *ast TSRMLS_DC) /* {{{ */
zend_compile_expr(result, expr_ast TSRMLS_CC);
}
end_silence = zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL TSRMLS_CC);
/* pair BEGIN_SILENCE and END_SILENCE opcodes */
end_silence->op2.num = opline_num;
end_opline_num = get_next_op_number(CG(active_op_array));
zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL TSRMLS_CC);
/* Store BEGIN_SILENCE/END_SILENCE pair to restore previous
* EG(error_reporting) value on exception */
brk_cont_element = get_next_brk_cont_element(CG(active_op_array));
brk_cont_element->start = begin_opline_num;
brk_cont_element->cont = brk_cont_element->brk = end_opline_num;
brk_cont_element->parent = -1;
}
/* }}} */

View File

@ -378,8 +378,6 @@ struct _zend_execute_data {
zend_array *symbol_table;
const zend_op *fast_ret; /* used by FAST_CALL/FAST_RET (finally keyword) */
zend_object *delayed_exception;
uint32_t silence_op_num;
uint32_t old_error_reporting;
};
#define VM_FRAME_KIND_MASK 0x000000ff

View File

@ -1486,7 +1486,6 @@ static zend_always_inline void i_init_func_execute_data(zend_execute_data *execu
EX(call) = NULL;
EX(return_value) = return_value;
EX(delayed_exception) = NULL;
EX(silence_op_num) = -1;
/* Handle arguments */
first_extra_arg = op_array->num_args;
@ -1553,7 +1552,6 @@ static zend_always_inline void i_init_code_execute_data(zend_execute_data *execu
EX(return_value) = return_value;
EX(scope) = EG(scope);
EX(delayed_exception) = NULL;
EX(silence_op_num) = -1;
zend_attach_symbol_table(execute_data);
@ -1580,7 +1578,6 @@ static zend_always_inline void i_init_execute_data(zend_execute_data *execute_da
EX(return_value) = return_value;
EX(scope) = EG(scope);
EX(delayed_exception) = NULL;
EX(silence_op_num) = -1;
if (UNEXPECTED(EX(symbol_table) != NULL)) {
zend_attach_symbol_table(execute_data);

View File

@ -5113,10 +5113,6 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY)
SAVE_OPLINE();
ZVAL_LONG(EX_VAR(opline->result.var), EG(error_reporting));
if (EX(silence_op_num) == -1) {
EX(silence_op_num) = opline->op2.num;
EX(old_error_reporting) = EG(error_reporting);
}
if (EG(error_reporting)) {
do {
@ -5154,9 +5150,6 @@ ZEND_VM_HANDLER(58, ZEND_END_SILENCE, TMP, ANY)
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(opline->op1.var)) != 0) {
EG(error_reporting) = Z_LVAL_P(EX_VAR(opline->op1.var));
}
if (EX(silence_op_num) == opline->op2.num) {
EX(silence_op_num) = -1;
}
ZEND_VM_NEXT_OPCODE();
}
@ -5522,17 +5515,16 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
}
} else if (brk_opline->opcode == ZEND_END_SILENCE) {
/* restore previous error_reporting value */
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var));
}
}
}
}
}
/* restore previous error_reporting value */
if (!EG(error_reporting) && EX(silence_op_num) != -1 && EX(old_error_reporting) != 0) {
EG(error_reporting) = EX(old_error_reporting);
}
EX(silence_op_num) = -1;
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
if (EX(delayed_exception)) {
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);

View File

@ -1029,10 +1029,6 @@ static int ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEND_OPCODE_HANDLER_AR
SAVE_OPLINE();
ZVAL_LONG(EX_VAR(opline->result.var), EG(error_reporting));
if (EX(silence_op_num) == -1) {
EX(silence_op_num) = opline->op2.num;
EX(old_error_reporting) = EG(error_reporting);
}
if (EG(error_reporting)) {
do {
@ -1264,17 +1260,16 @@ static int ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(ZEND_OPCODE_HANDLER
if (!(brk_opline->extended_value & EXT_TYPE_FREE_ON_RETURN)) {
zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var));
}
} else if (brk_opline->opcode == ZEND_END_SILENCE) {
/* restore previous error_reporting value */
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) {
EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var));
}
}
}
}
}
/* restore previous error_reporting value */
if (!EG(error_reporting) && EX(silence_op_num) != -1 && EX(old_error_reporting) != 0) {
EG(error_reporting) = EX(old_error_reporting);
}
EX(silence_op_num) = -1;
if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) {
if (EX(delayed_exception)) {
zend_exception_set_previous(EG(exception), EX(delayed_exception) TSRMLS_CC);
@ -10251,9 +10246,6 @@ static int ZEND_FASTCALL ZEND_END_SILENCE_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(opline->op1.var)) != 0) {
EG(error_reporting) = Z_LVAL_P(EX_VAR(opline->op1.var));
}
if (EX(silence_op_num) == opline->op2.num) {
EX(silence_op_num) = -1;
}
ZEND_VM_NEXT_OPCODE();
}

View File

@ -204,7 +204,8 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
j = 0;
for (i = 0; i< op_array->last_brk_cont; i++) {
if (op_array->brk_cont_array[i].start >= 0 &&
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE) {
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
int parent = op_array->brk_cont_array[i].parent;
while (parent >= 0 &&
@ -223,7 +224,8 @@ static int find_code_blocks(zend_op_array *op_array, zend_cfg *cfg, zend_optimiz
j = 0;
for (i = 0; i< op_array->last_brk_cont; i++) {
if (op_array->brk_cont_array[i].start >= 0 &&
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE) {
(op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_FREE ||
op_array->opcodes[op_array->brk_cont_array[i].brk].opcode == ZEND_END_SILENCE)) {
if (i != j) {
op_array->brk_cont_array[j] = op_array->brk_cont_array[i];
}