Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/PHP-7.0' into PHP-7.1
Browse files Browse the repository at this point in the history
  • Loading branch information
bwoebi committed Oct 18, 2016
2 parents c31d66b + 8b177f6 commit 58f3b9c
Show file tree
Hide file tree
Showing 3 changed files with 286 additions and 94 deletions.
18 changes: 18 additions & 0 deletions Zend/tests/bug73338.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Bug #73338: Ensure exceptions in function init opcodes are cleaned properly
--FILE--
<?php

try { call_user_func(new class { function __destruct () { throw new Error; } }); } catch (Error $e) {}

set_error_handler(function() { throw new Error; });

try { var_dump(new stdClass, call_user_func("fail")); } catch (Error $e) {}

try { (function() { call_user_func("fail"); })(); } catch (Error $e) {}

try { [new class { static function foo() {} function __destruct () { throw new Error; } }, "foo"](); } catch (Error $e) {}

?>
--EXPECTF--
Warning: call_user_func() expects parameter 1 to be a valid callback, no array or string given in %s on line %d
70 changes: 52 additions & 18 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -3234,15 +3234,19 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, CONST|T
GC_REFCOUNT(obj)++; /* For $this pointer */
}

FREE_OP2();
FREE_OP1();

if ((OP1_TYPE & (IS_VAR|IS_TMP_VAR)) && UNEXPECTED(EG(exception))) {
HANDLE_EXCEPTION();
}

call = zend_vm_stack_push_call_frame(call_info,
fbc, opline->extended_value, called_scope, obj);
call->prev_execute_data = EX(call);
EX(call) = call;

FREE_OP2();
FREE_OP1();

ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, CONST|TMPVAR|UNUSED|CONSTRUCTOR|CV, NUM)
Expand Down Expand Up @@ -3397,7 +3401,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
call->prev_execute_data = EX(call);
EX(call) = call;

ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM)
Expand Down Expand Up @@ -3461,12 +3465,26 @@ ZEND_VM_C_LABEL(try_function_name):
call = NULL;
}

FREE_OP2();

if (UNEXPECTED(!call)) {
HANDLE_EXCEPTION();
}

FREE_OP2();
if (OP2_TYPE & (IS_VAR|IS_TMP_VAR)) {
if (UNEXPECTED(EG(exception))) {
if (call) {
if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
zend_string_release(call->func->common.function_name);
zend_free_trampoline(call->func);
}
zend_vm_stack_free_call_frame(call);
}
HANDLE_EXCEPTION();
}
} else if (UNEXPECTED(!call)) {
HANDLE_EXCEPTION();
}

call->prev_execute_data = EX(call);
EX(call) = call;

Expand All @@ -3492,6 +3510,17 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
func = fcc.function_handler;
called_scope = fcc.called_scope;
object = fcc.object;
if (error) {
efree(error);
/* This is the only soft error is_callable() can generate */
zend_error(E_DEPRECATED,
"Non-static method %s::%s() should not be called statically",
ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name));
if (UNEXPECTED(EG(exception) != NULL)) {
FREE_OP2();
HANDLE_EXCEPTION();
}
}
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
/* Delay closure destruction until its invocation */
if (OP2_TYPE & (IS_VAR|IS_CV)) {
Expand All @@ -3504,22 +3533,28 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
call_info |= ZEND_CALL_RELEASE_THIS;
GC_REFCOUNT(object)++; /* For $this pointer */
}
if (error) {
efree(error);
/* This is the only soft error is_callable() can generate */
zend_error(E_DEPRECATED,
"Non-static method %s::%s() should not be called statically",
ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name));
if (UNEXPECTED(EG(exception) != NULL)) {
HANDLE_EXCEPTION();

FREE_OP2();
if ((OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
if (call_info & ZEND_CALL_CLOSURE) {
zend_object_release((zend_object*)func->common.prototype);
}
if (call_info & ZEND_CALL_RELEASE_THIS) {
zend_object_release(object);
}
HANDLE_EXCEPTION();
}

if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) {
init_func_run_time_cache(&func->op_array);
}
} else {
zend_internal_type_error(EX_USES_STRICT_TYPES(), "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(EX_CONSTANT(opline->op1)), error);
efree(error);
FREE_OP2();
if (UNEXPECTED(EG(exception))) {
HANDLE_EXCEPTION();
}
func = (zend_function*)&zend_pass_function;
called_scope = NULL;
object = NULL;
Expand All @@ -3530,8 +3565,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
call->prev_execute_data = EX(call);
EX(call) = call;

FREE_OP2();
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HANDLER(69, ZEND_INIT_NS_FCALL_BY_NAME, ANY, CONST, NUM)
Expand Down Expand Up @@ -4992,7 +5026,7 @@ ZEND_VM_HANDLER(68, ZEND_NEW, UNUSED|CLASS_FETCH|CONST|VAR, ANY, NUM)

call->prev_execute_data = EX(call);
EX(call) = call;
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
ZEND_VM_NEXT_OPCODE();
}

ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)
Expand Down
Loading

0 comments on commit 58f3b9c

Please sign in to comment.