Skip to content

Commit 30e866d

Browse files
committed
Various tweaks
1 parent 8491949 commit 30e866d

File tree

5 files changed

+121
-482
lines changed

5 files changed

+121
-482
lines changed

Zend/tests/gh20628_001.phpt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
Nullsafe operator does not support BP_VAR_W
3+
--FILE--
4+
<?php
5+
6+
function &test($foo) {
7+
return $foo?->bar();
8+
}
9+
10+
?>
11+
--EXPECTF--
12+
Fatal error: Cannot take reference of a nullsafe chain in %s on line %d

Zend/tests/gh20628_002.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Pipes support return-by-reference
3+
--FILE--
4+
<?php
5+
6+
function &foo($val) {
7+
global $x;
8+
$x = $val;
9+
return $x;
10+
}
11+
12+
function &bar() {
13+
return 42 |> foo(...);
14+
}
15+
16+
$xRef = &bar();
17+
$xRef++;
18+
var_dump($x);
19+
20+
?>
21+
--EXPECT--
22+
int(43)

Zend/zend_compile.c

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2600,8 +2600,7 @@ static void zend_emit_jmp_null(znode *obj_node, uint32_t bp_type)
26002600
zend_stack_push(&CG(short_circuiting_opnums), &jmp_null_opnum);
26012601
}
26022602

2603-
static inline bool zend_is_variable(const zend_ast *ast);
2604-
static inline bool zend_is_call(const zend_ast *ast);
2603+
static inline bool zend_is_variable_or_call(const zend_ast *ast);
26052604

26062605
static void zend_compile_memoized_expr(znode *result, zend_ast *expr, uint32_t type) /* {{{ */
26072606
{
@@ -2611,8 +2610,8 @@ static void zend_compile_memoized_expr(znode *result, zend_ast *expr, uint32_t t
26112610

26122611
/* Go through normal compilation */
26132612
CG(memoize_mode) = ZEND_MEMOIZE_NONE;
2614-
if (zend_is_variable(expr) || zend_is_call(expr)) {
2615-
zend_compile_var(result, expr, type, false);
2613+
if (zend_is_variable_or_call(expr)) {
2614+
zend_compile_var(result, expr, type, /* by_ref */ false);
26162615
} else {
26172616
zend_compile_expr(result, expr);
26182617
}
@@ -3852,7 +3851,7 @@ static uint32_t zend_compile_args(
38523851
if (zend_is_call(arg) || is_globals_fetch(arg)) {
38533852
uint32_t type = is_globals_fetch(arg) || (fbc && !ARG_SHOULD_BE_SENT_BY_REF(fbc, arg_num))
38543853
? BP_VAR_R : BP_VAR_FUNC_ARG;
3855-
zend_compile_var(&arg_node, arg, type, false);
3854+
zend_compile_var(&arg_node, arg, type, /* by_ref */ false);
38563855
if (arg_node.op_type & (IS_CONST|IS_TMP_VAR)) {
38573856
/* Function call was converted into builtin instruction */
38583857
if (!fbc || ARG_MUST_BE_SENT_BY_REF(fbc, arg_num)) {
@@ -4053,15 +4052,14 @@ static bool zend_compile_call_common(znode *result, zend_ast *args_ast, const ze
40534052
false
40544053
);
40554054
opline = zend_emit_op(result, call_op, NULL, NULL);
4056-
40574055
if (type == BP_VAR_R || type == BP_VAR_IS) {
40584056
if (init_opcode != ZEND_NEW && opline->result_type == IS_VAR) {
40594057
opline->result_type = IS_TMP_VAR;
40604058
result->op_type = IS_TMP_VAR;
40614059
}
40624060
}
40634061
if (may_have_extra_named_args) {
4064-
opline->extended_value |= ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
4062+
opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
40654063
}
40664064
opline->lineno = lineno;
40674065
zend_do_extended_fcall_end();
@@ -4404,11 +4402,11 @@ static zend_result zend_compile_func_cufa(znode *result, zend_ast_list *args, ze
44044402
zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL);
44054403
zend_emit_op(NULL, ZEND_CHECK_UNDEF_ARGS, NULL, NULL);
44064404
opline = zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL);
4407-
opline->extended_value |= ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
44084405
if (type == BP_VAR_R || type == BP_VAR_IS) {
44094406
opline->result_type = IS_TMP_VAR;
44104407
result->op_type = IS_TMP_VAR;
44114408
}
4409+
opline->extended_value = ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS;
44124410

44134411
return SUCCESS;
44144412
}
@@ -5870,8 +5868,7 @@ static void zend_compile_return(const zend_ast *ast) /* {{{ */
58705868
if (!expr_ast) {
58715869
expr_node.op_type = IS_CONST;
58725870
ZVAL_NULL(&expr_node.u.constant);
5873-
// FIXME: Shouldn't apply to nullsafe calls and pipes.
5874-
} else if (by_ref && (zend_is_variable(expr_ast) || zend_is_call(expr_ast))) {
5871+
} else if (by_ref && zend_is_variable_or_call(expr_ast)) {
58755872
zend_assert_not_short_circuited(expr_ast);
58765873
zend_compile_var(&expr_node, expr_ast, BP_VAR_W, true);
58775874
} else {
@@ -6710,7 +6707,7 @@ static void zend_compile_pipe(znode *result, zend_ast *ast, uint32_t type)
67106707

67116708
zend_do_extended_stmt(&operand_result);
67126709

6713-
zend_compile_var(result, fcall_ast, type, false);
6710+
zend_compile_var(result, fcall_ast, type, /* by_ref */ false);
67146711
}
67156712

67166713
static void zend_compile_match(znode *result, zend_ast *ast)
@@ -10907,7 +10904,7 @@ static void zend_compile_yield(znode *result, zend_ast *ast) /* {{{ */
1090710904
}
1090810905

1090910906
if (value_ast) {
10910-
if (returns_by_ref && (zend_is_variable(value_ast) || zend_is_call(value_ast))) {
10907+
if (returns_by_ref && zend_is_variable_or_call(value_ast)) {
1091110908
zend_assert_not_short_circuited(value_ast);
1091210909
zend_compile_var(&value_node, value_ast, BP_VAR_W, true);
1091310910
} else {
@@ -11966,7 +11963,7 @@ static void zend_compile_stmt(zend_ast *ast) /* {{{ */
1196611963
break;
1196711964
case ZEND_AST_ASSIGN: {
1196811965
znode result;
11969-
zend_compile_assign(&result, ast, true);
11966+
zend_compile_assign(&result, ast, /* stmt */ true);
1197011967
zend_do_free(&result);
1197111968
return;
1197211969
}
@@ -12019,7 +12016,7 @@ static void zend_compile_expr_inner(znode *result, zend_ast *ast) /* {{{ */
1201912016
zend_compile_var(result, ast, BP_VAR_R, false);
1202012017
return;
1202112018
case ZEND_AST_ASSIGN:
12022-
zend_compile_assign(result, ast, false);
12019+
zend_compile_assign(result, ast, /* stmt */ false);
1202312020
return;
1202412021
case ZEND_AST_ASSIGN_REF:
1202512022
zend_compile_assign_ref(result, ast, BP_VAR_R);

Zend/zend_vm_def.h

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2054,13 +2054,7 @@ ZEND_VM_COLD_CONSTCONST_HANDLER(93, ZEND_FETCH_DIM_FUNC_ARG, CONST|TMP|VAR|CV, C
20542054
if (OP1_TYPE & IS_VAR) {
20552055
zval *op1 = EX_VAR(opline->op1.var);
20562056
if (Z_TYPE_P(op1) == IS_REFERENCE) {
2057-
zend_reference *ref = Z_REF_P(op1);
2058-
ZVAL_COPY_VALUE(op1, &ref->val);
2059-
if (GC_DELREF(ref) == 0) {
2060-
efree_size(ref, sizeof(zend_reference));
2061-
} else {
2062-
Z_TRY_ADDREF_P(op1);
2063-
}
2057+
zend_unwrap_reference(op1);
20642058
}
20652059
}
20662060
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_DIM_R);
@@ -2432,13 +2426,7 @@ ZEND_VM_COLD_CONST_HANDLER(94, ZEND_FETCH_OBJ_FUNC_ARG, CONST|TMP|VAR|UNUSED|THI
24322426
if (OP1_TYPE == IS_VAR) {
24332427
zval *op1 = EX_VAR(opline->op1.var);
24342428
if (Z_TYPE_P(op1) == IS_REFERENCE) {
2435-
zend_reference *ref = Z_REF_P(op1);
2436-
ZVAL_COPY_VALUE(op1, &ref->val);
2437-
if (GC_DELREF(ref) == 0) {
2438-
efree_size(ref, sizeof(zend_reference));
2439-
} else {
2440-
Z_TRY_ADDREF_P(op1);
2441-
}
2429+
zend_unwrap_reference(op1);
24422430
}
24432431
}
24442432
ZEND_VM_DISPATCH_TO_HANDLER(ZEND_FETCH_OBJ_R);
@@ -4680,7 +4668,6 @@ ZEND_VM_COLD_CONST_HANDLER(111, ZEND_RETURN_BY_REF, CONST|TMP|VAR|CV, ANY, SRC,
46804668
ZEND_OBSERVER_FCALL_END(execute_data, return_value);
46814669
ZEND_OBSERVER_FREE_RETVAL();
46824670

4683-
// FIXME: Don't create the ref in the first place?
46844671
zend_return_unwrap_ref(execute_data, return_value);
46854672

46864673
ZEND_VM_DISPATCH_TO_HELPER(zend_leave_helper);
@@ -7279,9 +7266,10 @@ ZEND_VM_HOT_HANDLER(78, ZEND_FE_FETCH_R, TMP, ANY, JMP_ADDR)
72797266
zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES());
72807267
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
72817268
} else {
7282-
ZVAL_DEREF(value);
7283-
value_type = Z_TYPE_INFO_P(value);
7284-
7269+
if (UNEXPECTED(Z_ISREF_P(value))) {
7270+
value = Z_REFVAL_P(value);
7271+
value_type = Z_TYPE_INFO_P(value);
7272+
}
72857273
zval *res = EX_VAR(opline->op2.var);
72867274
zend_refcounted *gc = Z_COUNTED_P(value);
72877275

0 commit comments

Comments
 (0)