Skip to content

Commit 2b246e2

Browse files
committed
Merge branch 'PHP-7.1'
2 parents 81043bb + 58f3b9c commit 2b246e2

File tree

3 files changed

+286
-94
lines changed

3 files changed

+286
-94
lines changed

Zend/tests/bug73338.phpt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug #73338: Ensure exceptions in function init opcodes are cleaned properly
3+
--FILE--
4+
<?php
5+
6+
try { call_user_func(new class { function __destruct () { throw new Error; } }); } catch (Error $e) {}
7+
8+
set_error_handler(function() { throw new Error; });
9+
10+
try { var_dump(new stdClass, call_user_func("fail")); } catch (Error $e) {}
11+
12+
try { (function() { call_user_func("fail"); })(); } catch (Error $e) {}
13+
14+
try { [new class { static function foo() {} function __destruct () { throw new Error; } }, "foo"](); } catch (Error $e) {}
15+
16+
?>
17+
--EXPECTF--
18+
Warning: call_user_func() expects parameter 1 to be a valid callback, no array or string given in %s on line %d

Zend/zend_vm_def.h

+52-18
Original file line numberDiff line numberDiff line change
@@ -3234,15 +3234,19 @@ ZEND_VM_HANDLER(112, ZEND_INIT_METHOD_CALL, CONST|TMPVAR|UNUSED|THIS|CV, CONST|T
32343234
GC_REFCOUNT(obj)++; /* For $this pointer */
32353235
}
32363236

3237+
FREE_OP2();
3238+
FREE_OP1();
3239+
3240+
if ((OP1_TYPE & (IS_VAR|IS_TMP_VAR)) && UNEXPECTED(EG(exception))) {
3241+
HANDLE_EXCEPTION();
3242+
}
3243+
32373244
call = zend_vm_stack_push_call_frame(call_info,
32383245
fbc, opline->extended_value, called_scope, obj);
32393246
call->prev_execute_data = EX(call);
32403247
EX(call) = call;
32413248

3242-
FREE_OP2();
3243-
FREE_OP1();
3244-
3245-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
3249+
ZEND_VM_NEXT_OPCODE();
32463250
}
32473251

32483252
ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR, CONST|TMPVAR|UNUSED|CONSTRUCTOR|CV, NUM)
@@ -3397,7 +3401,7 @@ ZEND_VM_HANDLER(113, ZEND_INIT_STATIC_METHOD_CALL, UNUSED|CLASS_FETCH|CONST|VAR,
33973401
call->prev_execute_data = EX(call);
33983402
EX(call) = call;
33993403

3400-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
3404+
ZEND_VM_NEXT_OPCODE();
34013405
}
34023406

34033407
ZEND_VM_HANDLER(59, ZEND_INIT_FCALL_BY_NAME, ANY, CONST, NUM)
@@ -3461,12 +3465,26 @@ ZEND_VM_C_LABEL(try_function_name):
34613465
call = NULL;
34623466
}
34633467

3464-
FREE_OP2();
3465-
34663468
if (UNEXPECTED(!call)) {
34673469
HANDLE_EXCEPTION();
34683470
}
34693471

3472+
FREE_OP2();
3473+
if (OP2_TYPE & (IS_VAR|IS_TMP_VAR)) {
3474+
if (UNEXPECTED(EG(exception))) {
3475+
if (call) {
3476+
if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
3477+
zend_string_release(call->func->common.function_name);
3478+
zend_free_trampoline(call->func);
3479+
}
3480+
zend_vm_stack_free_call_frame(call);
3481+
}
3482+
HANDLE_EXCEPTION();
3483+
}
3484+
} else if (UNEXPECTED(!call)) {
3485+
HANDLE_EXCEPTION();
3486+
}
3487+
34703488
call->prev_execute_data = EX(call);
34713489
EX(call) = call;
34723490

@@ -3492,6 +3510,17 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
34923510
func = fcc.function_handler;
34933511
called_scope = fcc.called_scope;
34943512
object = fcc.object;
3513+
if (error) {
3514+
efree(error);
3515+
/* This is the only soft error is_callable() can generate */
3516+
zend_error(E_DEPRECATED,
3517+
"Non-static method %s::%s() should not be called statically",
3518+
ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name));
3519+
if (UNEXPECTED(EG(exception) != NULL)) {
3520+
FREE_OP2();
3521+
HANDLE_EXCEPTION();
3522+
}
3523+
}
34953524
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
34963525
/* Delay closure destruction until its invocation */
34973526
ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT);
@@ -3504,22 +3533,28 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
35043533
call_info |= ZEND_CALL_RELEASE_THIS;
35053534
GC_REFCOUNT(object)++; /* For $this pointer */
35063535
}
3507-
if (error) {
3508-
efree(error);
3509-
/* This is the only soft error is_callable() can generate */
3510-
zend_error(E_DEPRECATED,
3511-
"Non-static method %s::%s() should not be called statically",
3512-
ZSTR_VAL(func->common.scope->name), ZSTR_VAL(func->common.function_name));
3513-
if (UNEXPECTED(EG(exception) != NULL)) {
3514-
HANDLE_EXCEPTION();
3536+
3537+
FREE_OP2();
3538+
if ((OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
3539+
if (call_info & ZEND_CALL_CLOSURE) {
3540+
zend_object_release((zend_object*)func->common.prototype);
35153541
}
3542+
if (call_info & ZEND_CALL_RELEASE_THIS) {
3543+
zend_object_release(object);
3544+
}
3545+
HANDLE_EXCEPTION();
35163546
}
3547+
35173548
if (EXPECTED(func->type == ZEND_USER_FUNCTION) && UNEXPECTED(!func->op_array.run_time_cache)) {
35183549
init_func_run_time_cache(&func->op_array);
35193550
}
35203551
} else {
35213552
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);
35223553
efree(error);
3554+
FREE_OP2();
3555+
if (UNEXPECTED(EG(exception))) {
3556+
HANDLE_EXCEPTION();
3557+
}
35233558
func = (zend_function*)&zend_pass_function;
35243559
called_scope = NULL;
35253560
object = NULL;
@@ -3530,8 +3565,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
35303565
call->prev_execute_data = EX(call);
35313566
EX(call) = call;
35323567

3533-
FREE_OP2();
3534-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
3568+
ZEND_VM_NEXT_OPCODE();
35353569
}
35363570

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

49935027
call->prev_execute_data = EX(call);
49945028
EX(call) = call;
4995-
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
5029+
ZEND_VM_NEXT_OPCODE();
49965030
}
49975031

49985032
ZEND_VM_HANDLER(110, ZEND_CLONE, CONST|TMPVAR|UNUSED|THIS|CV, ANY)

0 commit comments

Comments
 (0)