Skip to content

Commit 166c0a7

Browse files
committed
Don't make argument nullable based on AST null initializer
1 parent 0b4e007 commit 166c0a7

File tree

8 files changed

+46
-74
lines changed

8 files changed

+46
-74
lines changed

Zend/tests/bug68446.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function a(array $a = FOO) {
99
var_dump($a);
1010
}
1111

12-
function b(array $b = BAR) {
12+
function b(?array $b = BAR) {
1313
var_dump($b);
1414
}
1515

Zend/tests/type_declarations/scalar_constant_defaults.phpt

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,10 @@ function int_val_default_null(int $a = NULL_VAL) {
3939
return $a;
4040
}
4141

42+
function nullable_int_val_default_null(?int $a = NULL_VAL) {
43+
return $a;
44+
}
45+
4246
echo "Testing int val" . PHP_EOL;
4347
var_dump(int_val());
4448

@@ -58,13 +62,27 @@ echo "Testing string add val" . PHP_EOL;
5862
var_dump(string_add_val());
5963

6064
echo "Testing int with default null constant" . PHP_EOL;
61-
var_dump(int_val_default_null());
65+
try {
66+
var_dump(int_val_default_null());
67+
} catch (TypeError $e) {
68+
echo $e->getMessage(), "\n";
69+
}
6270

6371
echo "Testing int with null null constant" . PHP_EOL;
64-
var_dump(int_val_default_null(null));
72+
try {
73+
var_dump(int_val_default_null(null));
74+
} catch (TypeError $e) {
75+
echo $e->getMessage(), "\n";
76+
}
77+
78+
echo "Testing nullable int with default null constant" . PHP_EOL;
79+
var_dump(nullable_int_val_default_null());
80+
81+
echo "Testing nullable int with null null constant" . PHP_EOL;
82+
var_dump(nullable_int_val_default_null(null));
6583

6684
?>
67-
--EXPECT--
85+
--EXPECTF--
6886
Testing int val
6987
int(10)
7088
Testing float val
@@ -78,6 +96,10 @@ float(10.7)
7896
Testing string add val
7997
string(14) "this is a test"
8098
Testing int with default null constant
81-
NULL
99+
Argument 1 passed to int_val_default_null() must be of the type int, null given, called in %s on line %d
82100
Testing int with null null constant
101+
Argument 1 passed to int_val_default_null() must be of the type int, null given, called in %s on line %d
102+
Testing nullable int with default null constant
103+
NULL
104+
Testing nullable int with null null constant
83105
NULL

Zend/zend_execute.c

Lines changed: 11 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -793,23 +793,6 @@ static ZEND_COLD void zend_verify_arg_error(
793793
}
794794
}
795795

796-
static int is_null_constant(zend_class_entry *scope, zval *default_value)
797-
{
798-
if (Z_TYPE_P(default_value) == IS_CONSTANT_AST) {
799-
zval constant;
800-
801-
ZVAL_COPY(&constant, default_value);
802-
if (UNEXPECTED(zval_update_constant_ex(&constant, scope) != SUCCESS)) {
803-
return 0;
804-
}
805-
if (Z_TYPE(constant) == IS_NULL) {
806-
return 1;
807-
}
808-
zval_ptr_dtor_nogc(&constant);
809-
}
810-
return 0;
811-
}
812-
813796
static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg)
814797
{
815798
switch (type_hint) {
@@ -1043,7 +1026,7 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf
10431026
static zend_always_inline zend_bool zend_check_type(
10441027
zend_type type,
10451028
zval *arg, zend_class_entry **ce, void **cache_slot,
1046-
zval *default_value, zend_class_entry *scope,
1029+
zend_class_entry *scope,
10471030
zend_bool is_return_type, zend_bool is_internal)
10481031
{
10491032
zend_reference *ref = NULL;
@@ -1063,19 +1046,19 @@ static zend_always_inline zend_bool zend_check_type(
10631046
} else {
10641047
*ce = zend_fetch_class(ZEND_TYPE_NAME(type), (ZEND_FETCH_CLASS_AUTO | ZEND_FETCH_CLASS_NO_AUTOLOAD));
10651048
if (UNEXPECTED(!*ce)) {
1066-
return Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value)));
1049+
return Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(type);
10671050
}
10681051
*cache_slot = (void *) *ce;
10691052
}
10701053
if (EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
10711054
return instanceof_function(Z_OBJCE_P(arg), *ce);
10721055
}
1073-
return Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value)));
1056+
return Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(type);
10741057
} else if (EXPECTED(ZEND_TYPE_CODE(type) == Z_TYPE_P(arg))) {
10751058
return 1;
10761059
}
10771060

1078-
if (Z_TYPE_P(arg) == IS_NULL && (ZEND_TYPE_ALLOW_NULL(type) || (default_value && is_null_constant(scope, default_value)))) {
1061+
if (Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(type)) {
10791062
/* Null passed to nullable type */
10801063
return 1;
10811064
}
@@ -1104,7 +1087,7 @@ static zend_always_inline zend_bool zend_check_type(
11041087
* because this case is already checked at compile-time. */
11051088
}
11061089

1107-
static zend_always_inline int zend_verify_recv_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot)
1090+
static zend_always_inline int zend_verify_recv_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot)
11081091
{
11091092
zend_arg_info *cur_arg_info = &zf->common.arg_info[arg_num-1];
11101093
zend_class_entry *ce;
@@ -1113,15 +1096,15 @@ static zend_always_inline int zend_verify_recv_arg_type(zend_function *zf, uint3
11131096
cur_arg_info = &zf->common.arg_info[arg_num-1];
11141097

11151098
ce = NULL;
1116-
if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, default_value, zf->common.scope, 0, 0))) {
1099+
if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, zf->common.scope, 0, 0))) {
11171100
zend_verify_arg_error(zf, cur_arg_info, arg_num, ce, arg);
11181101
return 0;
11191102
}
11201103

11211104
return 1;
11221105
}
11231106

1124-
static zend_always_inline int zend_verify_variadic_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, zval *default_value, void **cache_slot)
1107+
static zend_always_inline int zend_verify_variadic_arg_type(zend_function *zf, uint32_t arg_num, zval *arg, void **cache_slot)
11251108
{
11261109
zend_arg_info *cur_arg_info;
11271110
zend_class_entry *ce;
@@ -1131,7 +1114,7 @@ static zend_always_inline int zend_verify_variadic_arg_type(zend_function *zf, u
11311114
cur_arg_info = &zf->common.arg_info[zf->common.num_args];
11321115

11331116
ce = NULL;
1134-
if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, default_value, zf->common.scope, 0, 0))) {
1117+
if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, cache_slot, zf->common.scope, 0, 0))) {
11351118
zend_verify_arg_error(zf, cur_arg_info, arg_num, ce, arg);
11361119
return 0;
11371120
}
@@ -1158,7 +1141,7 @@ static zend_never_inline ZEND_ATTRIBUTE_UNUSED int zend_verify_internal_arg_type
11581141
break;
11591142
}
11601143

1161-
if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, &dummy_cache_slot, NULL, fbc->common.scope, 0, /* is_internal */ 1))) {
1144+
if (UNEXPECTED(!zend_check_type(cur_arg_info->type, arg, &ce, &dummy_cache_slot, fbc->common.scope, 0, /* is_internal */ 1))) {
11621145
return 0;
11631146
}
11641147
arg++;
@@ -1254,7 +1237,7 @@ static int zend_verify_internal_return_type(zend_function *zf, zval *ret)
12541237
return 1;
12551238
}
12561239

1257-
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, &dummy_cache_slot, NULL, NULL, 1, /* is_internal */ 1))) {
1240+
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, &dummy_cache_slot, NULL, 1, /* is_internal */ 1))) {
12581241
zend_verify_internal_return_error(zf, ce, ret);
12591242
return 0;
12601243
}
@@ -1268,7 +1251,7 @@ static zend_always_inline void zend_verify_return_type(zend_function *zf, zval *
12681251
zend_arg_info *ret_info = zf->common.arg_info - 1;
12691252
zend_class_entry *ce = NULL;
12701253

1271-
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, cache_slot, NULL, NULL, 1, 0))) {
1254+
if (UNEXPECTED(!zend_check_type(ret_info->type, ret, &ce, cache_slot, NULL, 1, 0))) {
12721255
zend_verify_return_error(zf, ce, ret);
12731256
}
12741257
}

Zend/zend_vm_def.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5198,7 +5198,7 @@ ZEND_VM_HOT_HANDLER(63, ZEND_RECV, NUM, UNUSED|CACHE_SLOT)
51985198
zval *param = EX_VAR(opline->result.var);
51995199

52005200
SAVE_OPLINE();
5201-
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) {
5201+
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num)) || EG(exception))) {
52025202
HANDLE_EXCEPTION();
52035203
}
52045204
}
@@ -5243,10 +5243,8 @@ ZEND_VM_HOT_HANDLER(64, ZEND_RECV_INIT, NUM, CONST, CACHE_SLOT)
52435243
}
52445244

52455245
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
5246-
zval *default_value = RT_CONSTANT(opline, opline->op2);
5247-
52485246
SAVE_OPLINE();
5249-
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)) || EG(exception))) {
5247+
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)) || EG(exception))) {
52505248
HANDLE_EXCEPTION();
52515249
}
52525250
}
@@ -5275,7 +5273,7 @@ ZEND_VM_HANDLER(164, ZEND_RECV_VARIADIC, NUM, UNUSED|CACHE_SLOT)
52755273
param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
52765274
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
52775275
do {
5278-
zend_verify_variadic_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num));
5276+
zend_verify_variadic_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num));
52795277
if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param);
52805278
ZEND_HASH_FILL_ADD(param);
52815279
param++;

Zend/zend_vm_execute.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3046,10 +3046,8 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_INIT_SPEC_CON
30463046
}
30473047

30483048
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
3049-
zval *default_value = RT_CONSTANT(opline, opline->op2);
3050-
30513049
SAVE_OPLINE();
3052-
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, default_value, CACHE_ADDR(opline->extended_value)) || EG(exception))) {
3050+
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->extended_value)) || EG(exception))) {
30533051
HANDLE_EXCEPTION();
30543052
}
30553053
}
@@ -3127,7 +3125,7 @@ static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_UNUSED_H
31273125
zval *param = EX_VAR(opline->result.var);
31283126

31293127
SAVE_OPLINE();
3130-
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num)) || EG(exception))) {
3128+
if (UNEXPECTED(!zend_verify_recv_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num)) || EG(exception))) {
31313129
HANDLE_EXCEPTION();
31323130
}
31333131
}
@@ -3155,7 +3153,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_VARIADIC_SPEC_UNUSED_HAND
31553153
param = EX_VAR_NUM(EX(func)->op_array.last_var + EX(func)->op_array.T);
31563154
if (UNEXPECTED((EX(func)->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0)) {
31573155
do {
3158-
zend_verify_variadic_arg_type(EX(func), arg_num, param, NULL, CACHE_ADDR(opline->op2.num));
3156+
zend_verify_variadic_arg_type(EX(func), arg_num, param, CACHE_ADDR(opline->op2.num));
31593157
if (Z_OPT_REFCOUNTED_P(param)) Z_ADDREF_P(param);
31603158
ZEND_HASH_FILL_ADD(param);
31613159
param++;

ext/opcache/Optimizer/zend_inference.c

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3104,11 +3104,6 @@ static int zend_update_type_info(const zend_op_array *op_array,
31043104
ce = NULL;
31053105
if (arg_info) {
31063106
tmp = zend_fetch_arg_info_type(script, arg_info, &ce);
3107-
if (opline->opcode == ZEND_RECV_INIT &&
3108-
Z_TYPE_P(CRT_CONSTANT_EX(op_array, opline, opline->op2, ssa->rt_constants)) == IS_CONSTANT_AST) {
3109-
/* The constant may resolve to NULL */
3110-
tmp |= MAY_BE_NULL;
3111-
}
31123107
if (arg_info->pass_by_reference) {
31133108
tmp |= MAY_BE_REF;
31143109
}

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,23 +1115,6 @@ static zval* ZEND_FASTCALL zend_jit_fetch_global_helper(zend_execute_data *execu
11151115
return value;
11161116
}
11171117

1118-
static int is_null_constant(zend_class_entry *scope, zval *default_value)
1119-
{
1120-
if (Z_CONSTANT_P(default_value)) {
1121-
zval constant;
1122-
1123-
ZVAL_COPY(&constant, default_value);
1124-
if (UNEXPECTED(zval_update_constant_ex(&constant, scope) != SUCCESS)) {
1125-
return 0;
1126-
}
1127-
if (Z_TYPE(constant) == IS_NULL) {
1128-
return 1;
1129-
}
1130-
zval_ptr_dtor(&constant);
1131-
}
1132-
return 0;
1133-
}
1134-
11351118
static zend_bool zend_verify_weak_scalar_type_hint(zend_uchar type_hint, zval *arg)
11361119
{
11371120
switch (type_hint) {
@@ -1313,12 +1296,11 @@ static void ZEND_FASTCALL zend_jit_verify_arg_object(zval *arg, zend_op_array *o
13131296
}
13141297
}
13151298

1316-
static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_op_array *op_array, uint32_t arg_num, zend_arg_info *arg_info, void **cache_slot, zval *default_value)
1299+
static void ZEND_FASTCALL zend_jit_verify_arg_slow(zval *arg, zend_op_array *op_array, uint32_t arg_num, zend_arg_info *arg_info, void **cache_slot)
13171300
{
13181301
zend_class_entry *ce = NULL;
13191302

1320-
if (Z_TYPE_P(arg) == IS_NULL &&
1321-
(ZEND_TYPE_ALLOW_NULL(arg_info->type) || (default_value && is_null_constant(op_array->scope, default_value)))) {
1303+
if (Z_TYPE_P(arg) == IS_NULL && ZEND_TYPE_ALLOW_NULL(arg_info->type)) {
13221304
/* Null passed to nullable type */
13231305
return;
13241306
}

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9021,16 +9021,13 @@ static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, zend_op_array
90219021
| mov CARG3, arg_num
90229022
| LOAD_ADDR CARG4, (ptrdiff_t)arg_info
90239023
| mov aword A5, r0
9024-
| mov aword A6, 0
90259024
| EXT_CALL zend_jit_verify_arg_slow, r0
90269025
|.elif X64
90279026
| mov CARG3, arg_num
90289027
| LOAD_ADDR CARG4, (ptrdiff_t)arg_info
90299028
| mov CARG5, r0
9030-
| xor CARG6, CARG6
90319029
| EXT_CALL zend_jit_verify_arg_slow, r0
90329030
|.else
9033-
| push 0
90349031
| push r0
90359032
| push (ptrdiff_t)arg_info
90369033
| push arg_num
@@ -9190,16 +9187,13 @@ static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, zend_op_a
91909187
| mov CARG3, arg_num
91919188
| LOAD_ADDR CARG4, (ptrdiff_t)arg_info
91929189
| mov aword A5, r0
9193-
| ADDR_OP2_2 mov, aword A6, zv, r0
91949190
| EXT_CALL zend_jit_verify_arg_slow, r0
91959191
|.elif X64
91969192
| mov CARG3, arg_num
91979193
| LOAD_ADDR CARG4, (ptrdiff_t)arg_info
91989194
| mov CARG5, r0
9199-
| LOAD_ADDR CARG6, zv
92009195
| EXT_CALL zend_jit_verify_arg_slow, r0
92019196
|.else
9202-
| push zv
92039197
| push r0
92049198
| push (ptrdiff_t)arg_info
92059199
| push arg_num

0 commit comments

Comments
 (0)