Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Zend/tests/partial_application/bound_arg_strict_types.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Partial application checks bound arguments with the creating scope's strict_types
--FILE--
<?php
declare(strict_types=1);

function f(int $a, $b) { return $a; }

try {
f("3", ?);
} catch (\TypeError $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}

function make() {
try {
f("3", ?);
} catch (\TypeError $e) {
echo $e::class, ": ", $e->getMessage(), "\n";
}
}
make();
?>
--EXPECT--
TypeError: f(): Argument #1 ($a) must be of type int, string given
TypeError: f(): Argument #1 ($a) must be of type int, string given
18 changes: 9 additions & 9 deletions Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -1153,7 +1153,7 @@ static bool zend_check_intersection_type_from_list(

static zend_always_inline bool zend_check_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref,
bool is_return_type, bool is_internal)
bool current_frame, bool is_internal)
{
if (ZEND_TYPE_IS_COMPLEX(*type) && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
zend_class_entry *ce;
Expand Down Expand Up @@ -1199,23 +1199,23 @@ static zend_always_inline bool zend_check_type_slow(
/* We cannot have conversions for typed refs. */
return 0;
}
if (is_internal && is_return_type) {
if (is_internal && current_frame) {
/* For internal returns, the type has to match exactly, because we're not
* going to check it for non-debug builds, and there will be no chance to
* apply coercions. */
return 0;
}

return zend_verify_scalar_type_hint(type_mask, arg,
is_return_type ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES(),
current_frame ? ZEND_RET_USES_STRICT_TYPES() : ZEND_ARG_USES_STRICT_TYPES(),
is_internal);

/* Special handling for IS_VOID is not necessary (for return types),
* because this case is already checked at compile-time. */
}

static zend_always_inline bool zend_check_type(
const zend_type *type, zval *arg, bool is_return_type, bool is_internal)
const zend_type *type, zval *arg, bool current_frame, bool is_internal)
{
const zend_reference *ref = NULL;
ZEND_ASSERT(ZEND_TYPE_IS_SET(*type));
Expand All @@ -1229,21 +1229,21 @@ static zend_always_inline bool zend_check_type(
return 1;
}

return zend_check_type_slow(type, arg, ref, is_return_type, is_internal);
return zend_check_type_slow(type, arg, ref, current_frame, is_internal);
}

/* We can not expose zend_check_type() directly because it's inline and uses static functions */
ZEND_API bool zend_check_type_ex(
const zend_type *type, zval *arg, bool is_return_type, bool is_internal)
const zend_type *type, zval *arg, bool current_frame, bool is_internal)
{
return zend_check_type(type, arg, is_return_type, is_internal);
return zend_check_type(type, arg, current_frame, is_internal);
}

ZEND_API bool zend_check_user_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type)
const zend_type *type, zval *arg, const zend_reference *ref, bool current_frame)
{
return zend_check_type_slow(
type, arg, ref, is_return_type, /* is_internal */ false);
type, arg, ref, current_frame, /* is_internal */ false);
}

static zend_always_inline bool zend_verify_recv_arg_type(const zend_function *zf, uint32_t arg_num, zval *arg)
Expand Down
4 changes: 2 additions & 2 deletions Zend/zend_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ ZEND_API zend_never_inline ZEND_COLD void zend_verify_never_error(
const zend_function *zf);
ZEND_API bool zend_verify_ref_array_assignable(zend_reference *ref);
ZEND_API bool zend_check_user_type_slow(
const zend_type *type, zval *arg, const zend_reference *ref, bool is_return_type);
const zend_type *type, zval *arg, const zend_reference *ref, bool current_frame);
ZEND_API bool zend_check_type_ex(
const zend_type *type, zval *arg, bool is_return_type, bool is_internal);
const zend_type *type, zval *arg, bool current_frame, bool is_internal);

#if ZEND_DEBUG
ZEND_API bool zend_internal_call_should_throw(const zend_function *fbc, zend_execute_data *call);
Expand Down
10 changes: 8 additions & 2 deletions Zend/zend_partial.c
Original file line number Diff line number Diff line change
Expand Up @@ -1098,8 +1098,14 @@ static void zp_bind(zval *result, zend_function *function, uint32_t argc, zval *
arg_info = NULL;
}
if (arg_info && ZEND_TYPE_IS_SET(arg_info->type)
&& UNEXPECTED(!zend_check_type_ex(&arg_info->type, var, 0, 0))) {
zend_verify_arg_error(function, arg_info, offset+1, var);
&& UNEXPECTED(!zend_check_type_ex(&arg_info->type, var,
/* current_frame */ true, /* is_internal */ false))) {
zend_string *need_msg = zend_type_to_string_resolved(arg_info->type,
function->common.scope);
zend_argument_type_error_ex(function, offset + 1,
"must be of type %s, %s given",
ZSTR_VAL(need_msg), zend_zval_value_name(var));
zend_string_release(need_msg);
zval_ptr_dtor(result);
ZVAL_NULL(result);
return;
Expand Down
4 changes: 2 additions & 2 deletions ext/opcache/jit/zend_jit_helpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -1974,7 +1974,7 @@ static bool ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_arg_info *arg
zend_execute_data *execute_data = EG(current_execute_data);
const zend_op *opline = EX(opline);
bool ret = zend_check_user_type_slow(
&arg_info->type, arg, /* ref */ NULL, /* is_return_type */ false);
&arg_info->type, arg, /* ref */ NULL, /* current_frame */ false);
if (UNEXPECTED(!ret)) {
zend_verify_arg_error(EX(func), arg_info, opline->op1.num, arg);
return false;
Expand All @@ -1991,7 +1991,7 @@ static void ZEND_FASTCALL zend_jit_verify_return_slow(zval *arg, const zend_op_a
}
}
if (UNEXPECTED(!zend_check_user_type_slow(
&arg_info->type, arg, /* ref */ NULL, /* is_return_type */ true))) {
&arg_info->type, arg, /* ref */ NULL, /* current_frame */ true))) {
zend_verify_return_error((zend_function*)op_array, arg);
}
}
Expand Down
Loading