Skip to content

Commit b6f76ac

Browse files
committed
Improve exception handling for abstract/deprecated calls
Reuse existing arg freeing loop instead of duplicating it. Additionally also handle deprecated in DO_FCALL_BY_NAME.
1 parent 4bb7282 commit b6f76ac

5 files changed

+119
-53
lines changed

Zend/tests/call_to_abstract_method_args.phpt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ try {
1313
echo $e->getMessage(), "\n";
1414
}
1515

16+
$ret = new stdClass;
17+
try {
18+
$ret = Test::method(new stdClass);
19+
} catch (Error $e) {
20+
echo $e->getMessage(), "\n";
21+
}
22+
1623
?>
1724
--EXPECT--
1825
Cannot call abstract method Test::method()
26+
Cannot call abstract method Test::method()
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
--TEST--
2+
Check that arguments are freed when calling a deprecated function
3+
--FILE--
4+
<?php
5+
6+
set_error_handler(function($code, $msg) {
7+
throw new Error($msg);
8+
});
9+
10+
try {
11+
ezmlm_hash(new stdClass);
12+
} catch (Error $e) {
13+
echo $e->getMessage(), "\n";
14+
}
15+
16+
$ret = new stdClass;
17+
try {
18+
$ret = ezmlm_hash(new stdClass);
19+
} catch (Error $e) {
20+
echo $e->getMessage(), "\n";
21+
}
22+
23+
try {
24+
$fn = 'ezmlm_hash';
25+
$fn(new stdClass);
26+
} catch (Error $e) {
27+
echo $e->getMessage(), "\n";
28+
}
29+
30+
$ret = new stdClass;
31+
try {
32+
$fn = 'ezmlm_hash';
33+
$ret = $fn(new stdClass);
34+
} catch (Error $e) {
35+
echo $e->getMessage(), "\n";
36+
}
37+
38+
?>
39+
--EXPECT--
40+
Function ezmlm_hash() is deprecated
41+
Function ezmlm_hash() is deprecated
42+
Function ezmlm_hash() is deprecated
43+
Function ezmlm_hash() is deprecated

Zend/zend_execute.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,6 @@ static zend_never_inline int zend_verify_internal_arg_types(zend_function *fbc,
11321132
dummy_cache_slot = NULL;
11331133
if (UNEXPECTED(!zend_verify_arg_type(fbc, i + 1, p, NULL, &dummy_cache_slot))) {
11341134
EG(current_execute_data) = call->prev_execute_data;
1135-
zend_vm_stack_free_args(call);
11361135
return 0;
11371136
}
11381137
p++;

Zend/zend_vm_def.h

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4075,8 +4075,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
40754075
if (UNEXPECTED((fbc->common.fn_flags & ZEND_ACC_DEPRECATED) != 0)) {
40764076
zend_deprecated_function(fbc);
40774077
if (UNEXPECTED(EG(exception) != NULL)) {
4078-
UNDEF_RESULT();
4079-
HANDLE_EXCEPTION();
4078+
UNDEF_RESULT();
4079+
if (!RETURN_VALUE_USED(opline)) {
4080+
ret = &retval;
4081+
ZVAL_UNDEF(ret);
4082+
}
4083+
ZEND_VM_C_GOTO(fcall_end);
40804084
}
40814085
}
40824086

@@ -4085,10 +4089,12 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
40854089

40864090
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
40874091
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
4088-
zend_vm_stack_free_call_frame(call);
4089-
zend_rethrow_exception(execute_data);
4090-
UNDEF_RESULT();
4091-
HANDLE_EXCEPTION();
4092+
UNDEF_RESULT();
4093+
if (!RETURN_VALUE_USED(opline)) {
4094+
ret = &retval;
4095+
ZVAL_UNDEF(ret);
4096+
}
4097+
ZEND_VM_C_GOTO(fcall_end);
40924098
}
40934099

40944100
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
@@ -4106,6 +4112,8 @@ ZEND_VM_HOT_HANDLER(131, ZEND_DO_FCALL_BY_NAME, ANY, ANY, SPEC(RETVAL))
41064112
#endif
41074113

41084114
EG(current_execute_data) = execute_data;
4115+
4116+
ZEND_VM_C_LABEL(fcall_end):
41094117
zend_vm_stack_free_args(call);
41104118
zend_vm_stack_free_call_frame(call);
41114119

@@ -4128,6 +4136,7 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
41284136
zend_execute_data *call = EX(call);
41294137
zend_function *fbc = call->func;
41304138
zval *ret;
4139+
zval retval;
41314140

41324141
SAVE_OPLINE();
41334142
EX(call) = call->prev_execute_data;
@@ -4136,7 +4145,10 @@ ZEND_VM_HOT_HANDLER(60, ZEND_DO_FCALL, ANY, ANY, SPEC(RETVAL))
41364145
zend_abstract_method(fbc);
41374146
ZEND_VM_C_LABEL(fcall_except):
41384147
UNDEF_RESULT();
4139-
zend_vm_stack_free_args(call);
4148+
if (!RETURN_VALUE_USED(opline)) {
4149+
ret = &retval;
4150+
ZVAL_UNDEF(ret);
4151+
}
41404152
ZEND_VM_C_GOTO(fcall_end);
41414153
} else {
41424154
zend_deprecated_function(fbc);
@@ -4167,15 +4179,12 @@ ZEND_VM_C_LABEL(fcall_except):
41674179
zend_execute_ex(call);
41684180
}
41694181
} else if (EXPECTED(fbc->type < ZEND_USER_FUNCTION)) {
4170-
zval retval;
4171-
41724182
call->prev_execute_data = execute_data;
41734183
EG(current_execute_data) = call;
41744184

41754185
if (UNEXPECTED(fbc->common.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)
41764186
&& UNEXPECTED(!zend_verify_internal_arg_types(fbc, call))) {
4177-
UNDEF_RESULT();
4178-
ZEND_VM_C_GOTO(fcall_end);
4187+
ZEND_VM_C_GOTO(fcall_except);
41794188
}
41804189

41814190
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
@@ -4198,15 +4207,13 @@ ZEND_VM_C_LABEL(fcall_except):
41984207
#endif
41994208

42004209
EG(current_execute_data) = execute_data;
4201-
zend_vm_stack_free_args(call);
42024210

4211+
ZEND_VM_C_LABEL(fcall_end):
4212+
zend_vm_stack_free_args(call);
42034213
if (!RETURN_VALUE_USED(opline)) {
42044214
i_zval_ptr_dtor(ret);
42054215
}
4206-
42074216
} else { /* ZEND_OVERLOADED_FUNCTION */
4208-
zval retval;
4209-
42104217
ret = RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : &retval;
42114218

42124219
call->prev_execute_data = execute_data;
@@ -4221,7 +4228,6 @@ ZEND_VM_C_LABEL(fcall_except):
42214228
}
42224229
}
42234230

4224-
ZEND_VM_C_LABEL(fcall_end):
42254231
if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) {
42264232
OBJ_RELEASE(Z_OBJ(call->This));
42274233
}
@@ -8291,14 +8297,13 @@ ZEND_VM_HANDLER(158, ZEND_CALL_TRAMPOLINE, ANY, ANY)
82918297

82928298
EG(current_execute_data) = call->prev_execute_data;
82938299

8300+
ZEND_VM_C_LABEL(call_trampoline_end):
82948301
zend_vm_stack_free_args(call);
8295-
82968302
if (ret == &retval) {
82978303
zval_ptr_dtor(ret);
82988304
}
82998305
}
83008306

8301-
ZEND_VM_C_LABEL(call_trampoline_end):
83028307
execute_data = EG(current_execute_data);
83038308

83048309
if (!EX(func) || !ZEND_USER_CODE(EX(func)->type) || (call_info & ZEND_CALL_TOP)) {

0 commit comments

Comments
 (0)