Skip to content

Commit

Permalink
Check internal function type consistency in zend_call_function
Browse files Browse the repository at this point in the history
We do this for calls in the engine, but not those going through
zend_call_function().
  • Loading branch information
nikic committed Jul 13, 2021
1 parent 6777630 commit ee65e92
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 3 deletions.
6 changes: 3 additions & 3 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1145,7 +1145,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED bool zend_verify_internal_arg_typ
/* Determine whether an internal call should throw, because the passed arguments violate
* an arginfo constraint. This is only checked in debug builds. In release builds, we
* trust that arginfo matches what is enforced by zend_parse_parameters. */
static zend_always_inline bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call)
ZEND_API bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call)
{
if (fbc->internal_function.handler == ZEND_FN(pass)) {
/* Be lenient about the special pass function. */
Expand All @@ -1172,7 +1172,7 @@ static zend_always_inline bool zend_internal_call_should_throw(zend_function *fb
return 0;
}

static ZEND_COLD void zend_internal_call_arginfo_violation(zend_function *fbc)
ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(zend_function *fbc)
{
zend_error(E_ERROR, "Arginfo / zpp mismatch during call of %s%s%s()",
fbc->common.scope ? ZSTR_VAL(fbc->common.scope->name) : "",
Expand Down Expand Up @@ -1274,7 +1274,7 @@ static ZEND_COLD void zend_verify_void_return_error(const zend_function *zf, con
fclass, fsep, fname, returned_msg, returned_kind);
}

static bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret)
{
zend_internal_arg_info *ret_info = zf->internal_function.arg_info - 1;

Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,11 @@ ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref);
ZEND_API bool zend_check_user_type_slow(
zend_type *type, zval *arg, zend_reference *ref, void **cache_slot, bool is_return_type);

#if ZEND_DEBUG
ZEND_API bool zend_internal_call_should_throw(zend_function *fbc, zend_execute_data *call);
ZEND_API ZEND_COLD void zend_internal_call_arginfo_violation(zend_function *fbc);
ZEND_API bool zend_verify_internal_return_type(zend_function *zf, zval *ret);
#endif

#define ZEND_REF_TYPE_SOURCES(ref) \
(ref)->sources
Expand Down
15 changes: 15 additions & 0 deletions Zend/zend_execute_API.c
Original file line number Diff line number Diff line change
Expand Up @@ -887,6 +887,9 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
EG(jit_trace_num) = orig_jit_trace_num;
} else {
ZEND_ASSERT(func->type == ZEND_INTERNAL_FUNCTION);
#if ZEND_DEBUG
bool should_throw = zend_internal_call_should_throw(func, call);
#endif
ZVAL_NULL(fci->retval);
call->prev_execute_data = EG(current_execute_data);
EG(current_execute_data) = call;
Expand All @@ -902,6 +905,18 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
zend_array_release(call->extra_named_params);
}

#if ZEND_DEBUG
if (!EG(exception) && call->func) {
if (should_throw) {
zend_internal_call_arginfo_violation(call->func);
}
ZEND_ASSERT(!(call->func->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) ||
zend_verify_internal_return_type(call->func, fci->retval));
ZEND_ASSERT((call->func->common.fn_flags & ZEND_ACC_RETURN_REFERENCE)
? Z_ISREF_P(fci->retval) : !Z_ISREF_P(fci->retval));
}
#endif

if (EG(exception)) {
zval_ptr_dtor(fci->retval);
ZVAL_UNDEF(fci->retval);
Expand Down

0 comments on commit ee65e92

Please sign in to comment.