Skip to content

Commit 9068bce

Browse files
committed
Remove support for ZEND_SEND_USER
1 parent b3a6425 commit 9068bce

13 files changed

+110
-221
lines changed

Zend/tests/explicitSendByRef/__call.phpt

+7-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,11 @@ class ForwardCalls {
2222
$forward = new ForwardCalls(new Incrementor);
2323

2424
$i = 0;
25-
$forward->inc(&$i);
25+
try {
26+
$forward->inc(&$i);
27+
} catch (Error $e) {
28+
echo $e->getMessage(), "\n";
29+
}
2630
var_dump($i);
2731

2832
$i = 0;
@@ -31,5 +35,6 @@ var_dump($i);
3135

3236
?>
3337
--EXPECT--
34-
int(1)
38+
Cannot pass reference to by-value parameter 1
39+
int(0)
3540
int(0)

Zend/tests/explicitSendByRef/basic.phpt

+16-5
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,10 @@ var_dump($b);
1414

1515
// Works (prefer-ref arg)
1616
$c = 42;
17-
$vars = ['d' => &$c];
18-
extract(&$vars, EXTR_REFS);
19-
$d++;
20-
var_dump($c);
17+
$vars = ['b' => 2, 'a' => 1];
18+
$vars2 = [2, 1];
19+
array_multisort(&$vars, $vars2);
20+
var_dump($vars, $vars2);
2121

2222
// Works (by-ref arg, by-ref function)
2323
$e = 42;
@@ -68,7 +68,18 @@ array(1) {
6868
int(43)
6969
}
7070
}
71-
int(43)
71+
array(2) {
72+
["a"]=>
73+
int(1)
74+
["b"]=>
75+
int(2)
76+
}
77+
array(2) {
78+
[0]=>
79+
int(1)
80+
[1]=>
81+
int(2)
82+
}
7283
int(43)
7384
Cannot pass reference to by-value parameter 1
7485
Cannot pass result of by-value function by reference

Zend/tests/explicitSendByRef/call_user_func.phpt

+1-22
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,12 @@ call_user_func() with explicit pass by ref
33
--FILE--
44
<?php
55

6-
// Avoid VM builtin.
7-
namespace Foo;
8-
96
function inc(&$i) { $i++; }
107

11-
$i = 0;
12-
call_user_func('Foo\inc', $i);
13-
var_dump($i);
14-
158
$i = 0;
169
call_user_func('Foo\inc', &$i);
1710
var_dump($i);
1811

19-
$i = 0;
20-
\call_user_func('Foo\inc', $i);
21-
var_dump($i);
22-
23-
$i = 0;
24-
\call_user_func('Foo\inc', &$i);
25-
var_dump($i);
26-
2712
?>
2813
--EXPECTF--
29-
Warning: Foo\inc(): Argument #1 ($i) must be passed by reference, value given in %s on line %d
30-
int(0)
31-
int(1)
32-
33-
Warning: Foo\inc(): Argument #1 ($i) must be passed by reference, value given in %s on line %d
34-
int(0)
35-
int(1)
14+
Fatal error: Cannot pass reference to by-value parameter 2 in %s on line %d

Zend/zend_compile.c

+4-6
Original file line numberDiff line numberDiff line change
@@ -4301,19 +4301,16 @@ static zend_result zend_compile_func_cuf(znode *result, zend_ast_list *args, zen
43014301
zend_ast *arg_ast = args->child[i];
43024302
znode arg_node;
43034303
zend_op *opline;
4304-
bool by_ref = 0;
43054304

43064305
if (arg_ast->kind == ZEND_AST_REF) {
4307-
zend_compile_var(&arg_node, arg_ast->child[0], BP_VAR_W, 1);
4308-
by_ref = 1;
4309-
} else {
4310-
zend_compile_expr(&arg_node, arg_ast);
4306+
zend_error_noreturn(E_COMPILE_ERROR,
4307+
"Cannot pass reference to by-value parameter %" PRIu32, i + 1);
43114308
}
4309+
zend_compile_expr(&arg_node, arg_ast);
43124310

43134311
opline = zend_emit_op(NULL, ZEND_SEND_USER, &arg_node, NULL);
43144312
opline->op2.num = i;
43154313
opline->result.var = EX_NUM_TO_VAR(i - 1);
4316-
opline->extended_value = by_ref;
43174314
}
43184315
zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
43194316

@@ -6602,6 +6599,7 @@ static void zend_compile_declare(zend_ast *ast) /* {{{ */
66026599
if (Z_LVAL(value_zv) == 1) {
66036600
CG(active_op_array)->fn_flags |= ZEND_ACC_STRICT_TYPES;
66046601
}
6602+
66056603
} else {
66066604
zend_error(E_COMPILE_WARNING, "Unsupported declare '%s'", ZSTR_VAL(name));
66076605
}

Zend/zend_compile.h

+13-41
Original file line numberDiff line numberDiff line change
@@ -1044,8 +1044,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
10441044

10451045
#define ZEND_SEND_BY_VAL 0u
10461046
#define ZEND_SEND_BY_REF 1u
1047-
#define ZEND_SEND_PREFER_VAL 2u
1048-
#define ZEND_SEND_PREFER_REF 3u
1047+
#define ZEND_SEND_PREFER_REF 2u
10491048

10501049
#define ZEND_THROW_IS_EXPR 1u
10511050

@@ -1078,7 +1077,7 @@ ZEND_API zend_string *zend_type_to_string(zend_type type);
10781077
#define IS_CONSTANT_CLASS 0x400 /* __CLASS__ in trait */
10791078
#define IS_CONSTANT_UNQUALIFIED_IN_NAMESPACE 0x800
10801079

1081-
static zend_always_inline bool zend_check_arg_must_be_sent_by_ref(const zend_function *zf, uint32_t arg_num)
1080+
static zend_always_inline bool zend_check_arg_send_type(const zend_function *zf, uint32_t arg_num, uint32_t mask)
10821081
{
10831082
arg_num--;
10841083
if (UNEXPECTED(arg_num >= zf->common.num_args)) {
@@ -1087,44 +1086,17 @@ static zend_always_inline bool zend_check_arg_must_be_sent_by_ref(const zend_fun
10871086
}
10881087
arg_num = zf->common.num_args;
10891088
}
1090-
return ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) == ZEND_SEND_BY_REF;
1091-
}
1092-
1093-
static zend_always_inline int zend_check_arg_should_be_sent_by_ref(const zend_function *zf, uint32_t arg_num)
1094-
{
1095-
arg_num--;
1096-
if (UNEXPECTED(arg_num >= zf->common.num_args)) {
1097-
if (EXPECTED((zf->common.fn_flags & ZEND_ACC_VARIADIC) == 0)) {
1098-
return 0;
1099-
}
1100-
arg_num = zf->common.num_args;
1101-
}
1102-
1103-
/* The SEND_BY_REF bit is set for PREFER_REF as well. */
1104-
return (ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) & ZEND_SEND_BY_REF) != 0;
1105-
}
1106-
1107-
static zend_always_inline int zend_check_arg_may_be_sent_by_ref(const zend_function *zf, uint32_t arg_num)
1108-
{
1109-
arg_num--;
1110-
if (UNEXPECTED(arg_num >= zf->common.num_args)) {
1111-
if (EXPECTED((zf->common.fn_flags & ZEND_ACC_VARIADIC) == 0)) {
1112-
return 0;
1113-
}
1114-
arg_num = zf->common.num_args;
1115-
}
1116-
1117-
return ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) != ZEND_SEND_BY_VAL;
1089+
return UNEXPECTED((ZEND_ARG_SEND_MODE(&zf->common.arg_info[arg_num]) & mask) != 0);
11181090
}
11191091

11201092
#define ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \
1121-
zend_check_arg_must_be_sent_by_ref(zf, arg_num)
1093+
zend_check_arg_send_type(zf, arg_num, ZEND_SEND_BY_REF)
11221094

11231095
#define ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \
1124-
zend_check_arg_should_be_sent_by_ref(zf, arg_num)
1096+
zend_check_arg_send_type(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF)
11251097

11261098
#define ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \
1127-
zend_check_arg_may_be_sent_by_ref(zf, arg_num)
1099+
zend_check_arg_send_type(zf, arg_num, ZEND_SEND_PREFER_REF)
11281100

11291101
/* Quick API to check first 12 arguments */
11301102
#define MAX_ARG_FLAG_NUM 12
@@ -1133,24 +1105,24 @@ static zend_always_inline int zend_check_arg_may_be_sent_by_ref(const zend_funct
11331105
# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \
11341106
(zf)->quick_arg_flags |= ((mask) << ((arg_num) - 1) * 2); \
11351107
} while (0)
1136-
# define ZEND_GET_ARG_FLAG(zf, arg_num) \
1137-
(((zf)->quick_arg_flags >> (((arg_num) - 1) * 2)) & 0x3u)
1108+
# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \
1109+
(((zf)->quick_arg_flags >> (((arg_num) - 1) * 2)) & (mask))
11381110
#else
11391111
# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \
11401112
(zf)->quick_arg_flags |= (((mask) << 6) << (arg_num) * 2); \
11411113
} while (0)
1142-
# define ZEND_GET_ARG_FLAG(zf, arg_num) \
1143-
(((zf)->quick_arg_flags >> (((arg_num) + 3) * 2)) & 0x3u)
1114+
# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \
1115+
(((zf)->quick_arg_flags >> (((arg_num) + 3) * 2)) & (mask))
11441116
#endif
11451117

11461118
#define QUICK_ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \
1147-
(ZEND_GET_ARG_FLAG(zf, arg_num) == ZEND_SEND_BY_REF)
1119+
ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF)
11481120

11491121
#define QUICK_ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \
1150-
((ZEND_GET_ARG_FLAG(zf, arg_num) & ZEND_SEND_BY_REF) != 0)
1122+
ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF)
11511123

11521124
#define QUICK_ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \
1153-
(ZEND_GET_ARG_FLAG(zf, arg_num) != ZEND_SEND_BY_VAL)
1125+
ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_PREFER_REF)
11541126

11551127
#define ZEND_RETURN_VAL 0
11561128
#define ZEND_RETURN_REF 1

Zend/zend_execute_API.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -847,7 +847,7 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
847847

848848
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
849849
if (UNEXPECTED(!Z_ISREF_P(arg))) {
850-
if (ARG_MUST_BE_SENT_BY_REF(func, i + 1)) {
850+
if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
851851
/* By-value send is not allowed -- emit a warning,
852852
* and perform the call with the value wrapped in a reference. */
853853
zend_param_must_be_ref(func, i + 1);
@@ -905,7 +905,7 @@ zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_
905905

906906
if (ARG_SHOULD_BE_SENT_BY_REF(func, arg_num)) {
907907
if (UNEXPECTED(!Z_ISREF_P(arg))) {
908-
if (ARG_MUST_BE_SENT_BY_REF(func, arg_num)) {
908+
if (!ARG_MAY_BE_SENT_BY_REF(func, arg_num)) {
909909
/* By-value send is not allowed -- emit a warning,
910910
* and perform the call with the value wrapped in a reference. */
911911
zend_param_must_be_ref(func, arg_num);

Zend/zend_object_handlers.c

+5-11
Original file line numberDiff line numberDiff line change
@@ -1317,10 +1317,6 @@ ZEND_API bool zend_check_protected(const zend_class_entry *ce, const zend_class_
13171317
}
13181318
/* }}} */
13191319

1320-
ZEND_BEGIN_ARG_INFO_EX(zend_call_arg_info, 0, 0, 0)
1321-
ZEND_ARG_VARIADIC_INFO(ZEND_SEND_PREFER_VAL, args)
1322-
ZEND_END_ARG_INFO()
1323-
13241320
ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce, zend_string *method_name, bool is_static) /* {{{ */
13251321
{
13261322
size_t mname_len;
@@ -1330,9 +1326,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce
13301326
* The low bit must be zero, to not be interpreted as a MAP_PTR offset.
13311327
*/
13321328
static const void *dummy = (void*)(intptr_t)2;
1333-
unsigned char arg_flags =
1334-
(ZEND_SEND_PREFER_VAL << 6) | (ZEND_SEND_PREFER_VAL << 4) |
1335-
(ZEND_SEND_PREFER_VAL << 2) | ZEND_SEND_PREFER_VAL;
1329+
static const zend_arg_info arg_info[1] = {{0}};
13361330

13371331
ZEND_ASSERT(fbc);
13381332

@@ -1343,9 +1337,9 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce
13431337
}
13441338

13451339
func->type = ZEND_USER_FUNCTION;
1346-
func->arg_flags[0] = arg_flags;
1347-
func->arg_flags[1] = arg_flags;
1348-
func->arg_flags[2] = arg_flags;
1340+
func->arg_flags[0] = 0;
1341+
func->arg_flags[1] = 0;
1342+
func->arg_flags[2] = 0;
13491343
func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC | ZEND_ACC_VARIADIC;
13501344
if (is_static) {
13511345
func->fn_flags |= ZEND_ACC_STATIC;
@@ -1376,7 +1370,7 @@ ZEND_API zend_function *zend_get_call_trampoline_func(const zend_class_entry *ce
13761370
func->prototype = NULL;
13771371
func->num_args = 0;
13781372
func->required_num_args = 0;
1379-
func->arg_info = (zend_arg_info *) zend_call_arg_info + 1;
1373+
func->arg_info = (zend_arg_info *) arg_info;
13801374

13811375
return (zend_function*)func;
13821376
}

Zend/zend_vm_def.h

+15-25
Original file line numberDiff line numberDiff line change
@@ -4889,7 +4889,7 @@ ZEND_VM_HOT_SEND_HANDLER(50, ZEND_SEND_VAR_NO_REF_EX, VAR, CONST|UNUSED|NUM, SPE
48894889
ZVAL_COPY_VALUE(arg, varptr);
48904890

48914891
if (EXPECTED(Z_ISREF_P(varptr) ||
4892-
!ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
4892+
QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
48934893
ZEND_VM_NEXT_OPCODE();
48944894
}
48954895
} else {
@@ -4901,7 +4901,7 @@ ZEND_VM_HOT_SEND_HANDLER(50, ZEND_SEND_VAR_NO_REF_EX, VAR, CONST|UNUSED|NUM, SPE
49014901
ZVAL_COPY_VALUE(arg, varptr);
49024902

49034903
if (EXPECTED(Z_ISREF_P(varptr) ||
4904-
!ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
4904+
ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num))) {
49054905
ZEND_VM_NEXT_OPCODE();
49064906
}
49074907
}
@@ -4966,10 +4966,10 @@ ZEND_VM_HANDLER(209, ZEND_SEND_EXPLICIT_REF, VAR|CV, NUM, SPEC(QUICK_ARG))
49664966
uint32_t arg_num = opline->op2.num;
49674967

49684968
if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) {
4969-
if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
4969+
if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
49704970
ZEND_VM_C_GOTO(invalid_send_ref);
49714971
}
4972-
} else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
4972+
} else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
49734973
ZEND_VM_C_LABEL(invalid_send_ref):
49744974
SAVE_OPLINE();
49754975
zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num);
@@ -5000,10 +5000,10 @@ ZEND_VM_HANDLER(210, ZEND_SEND_EXPLICIT_REF_FUNC, VAR, NUM)
50005000
uint32_t arg_num = opline->op2.num;
50015001

50025002
if (EXPECTED(arg_num <= MAX_ARG_FLAG_NUM)) {
5003-
if (!QUICK_ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
5003+
if (!QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
50045004
ZEND_VM_C_GOTO(invalid_send_ref);
50055005
}
5006-
} else if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
5006+
} else if (!ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
50075007
ZEND_VM_C_LABEL(invalid_send_ref):
50085008
SAVE_OPLINE();
50095009
zend_throw_error(NULL, "Cannot pass reference to by-value parameter %" PRIu32, arg_num);
@@ -5455,7 +5455,7 @@ ZEND_VM_C_LABEL(send_array):
54555455
break;
54565456
} else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
54575457
if (UNEXPECTED(!Z_ISREF_P(arg))) {
5458-
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
5458+
if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
54595459
/* By-value send is not allowed -- emit a warning,
54605460
* but still perform the call. */
54615461
zend_param_must_be_ref(EX(call)->func, arg_num);
@@ -5507,7 +5507,7 @@ ZEND_VM_C_LABEL(send_array):
55075507
bool must_wrap = 0;
55085508
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
55095509
if (UNEXPECTED(!Z_ISREF_P(arg))) {
5510-
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
5510+
if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
55115511
/* By-value send is not allowed -- emit a warning,
55125512
* but still perform the call. */
55135513
zend_param_must_be_ref(EX(call)->func, arg_num);
@@ -5540,31 +5540,21 @@ ZEND_VM_C_LABEL(send_array):
55405540
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
55415541
}
55425542

5543-
ZEND_VM_HANDLER(120, ZEND_SEND_USER, CONST|TMP|VAR|CV, NUM, REF)
5543+
ZEND_VM_HANDLER(120, ZEND_SEND_USER, CONST|TMP|VAR|CV, NUM)
55445544
{
55455545
USE_OPLINE
55465546
zval *arg, *param;
55475547

55485548
SAVE_OPLINE();
55495549

5550+
arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
55505551
param = ZEND_CALL_VAR(EX(call), opline->result.var);
5551-
if (opline->extended_value) {
5552-
arg = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
5553-
if (Z_ISREF_P(arg)) {
5554-
Z_ADDREF_P(arg);
5555-
} else {
5556-
ZVAL_MAKE_REF_EX(arg, 2);
5557-
}
5558-
ZVAL_REF(param, Z_REF_P(arg));
5552+
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
5553+
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
5554+
Z_TRY_ADDREF_P(arg);
5555+
ZVAL_NEW_REF(param, arg);
55595556
} else {
5560-
arg = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
5561-
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
5562-
zend_param_must_be_ref(EX(call)->func, opline->op2.num);
5563-
Z_TRY_ADDREF_P(arg);
5564-
ZVAL_NEW_REF(param, arg);
5565-
} else {
5566-
ZVAL_COPY(param, arg);
5567-
}
5557+
ZVAL_COPY(param, arg);
55685558
}
55695559

55705560
FREE_OP1();

0 commit comments

Comments
 (0)