Skip to content

Commit 91314f3

Browse files
committed
Improve error message for 'Cannot pass parameter by reference'
1 parent 517c993 commit 91314f3

26 files changed

+111
-64
lines changed

Zend/tests/bug72038.phpt

Lines changed: 9 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,25 @@ Bug #72038 (Function calls with values to a by-ref parameter don't always throw
66
try {
77
test($foo = new stdClass);
88
var_dump($foo);
9-
} catch (Throwable $e) {
10-
echo "Exception: " . $e->getMessage() . "\n";
9+
} catch (Error $e) {
10+
echo $e->getMessage() . "\n";
1111
}
1212
try {
1313
test($bar = 2);
1414
var_dump($bar);
15-
} catch (Throwable $e) {
16-
echo "Exception: " . $e->getMessage() . "\n";
17-
}
18-
try {
19-
test($baz = &$bar);
20-
var_dump($baz);
21-
} catch (Throwable $e) {
22-
echo "Exception: " . $e->getMessage() . "\n";
15+
} catch (Error $e) {
16+
echo $e->getMessage() . "\n";
2317
}
2418

19+
test($baz = &$bar);
20+
var_dump($baz);
21+
2522
function test(&$param) {
2623
$param = 1;
2724
}
2825

2926
?>
3027
--EXPECT--
31-
Exception: Cannot pass parameter 1 by reference
32-
Exception: Cannot pass parameter 1 by reference
28+
test(): Argument #1 ($param) cannot be passed by reference
29+
test(): Argument #1 ($param) cannot be passed by reference
3330
int(1)

Zend/tests/bug73663_2.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ change(list($val) = $array);
1212
var_dump($array);
1313
?>
1414
--EXPECTF--
15-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
15+
Fatal error: Uncaught Error: change(): Argument #1 ($ref) cannot be passed by reference in %s:%d
1616
Stack trace:
1717
#0 {main}
1818
thrown in %s on line %d

Zend/tests/bug78154.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ namespace Foo {
2222

2323
?>
2424
--EXPECT--
25-
Exception: Cannot pass parameter 3 by reference
26-
Exception: Cannot pass parameter 3 by reference
25+
Exception: similar_text(): Argument #3 ($percent) cannot be passed by reference
26+
Exception: similar_text(): Argument #3 ($percent) cannot be passed by reference

Zend/tests/bug79783.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ Bug #79783: Segfault in php_str_replace_common
55
str_replace("a", "b", "c", strlen("d"));
66
?>
77
--EXPECTF--
8-
Fatal error: Uncaught Error: Cannot pass parameter 4 by reference in %s:%d
8+
Fatal error: Uncaught Error: str_replace(): Argument #4 ($replace_count) cannot be passed by reference in %s:%d
99
Stack trace:
1010
#0 {main}
1111
thrown in %s on line %d

Zend/tests/closure_019.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ int(9)
2626
Notice: Only variable references should be returned by reference in %sclosure_019.php on line 4
2727
int(81)
2828

29-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
29+
Fatal error: Uncaught Error: {closure}(): Argument #1 ($x) cannot be passed by reference in %s:%d
3030
Stack trace:
3131
#0 %s(%d): test()
3232
#1 {main}

Zend/tests/errmsg_022.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ foo(1);
1111
echo "Done\n";
1212
?>
1313
--EXPECTF--
14-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
14+
Fatal error: Uncaught Error: foo(): Argument #1 ($var) cannot be passed by reference in %s:%d
1515
Stack trace:
1616
#0 {main}
1717
thrown in %s on line %d

Zend/tests/match/027.phpt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ main();
3030
usesValue 0
3131
i is 0
3232

33-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s027.php:20
33+
Fatal error: Uncaught Error: Test::usesRef(): Argument #1 ($x) cannot be passed by reference in %s:%d
3434
Stack trace:
35-
#0 %s027.php(23): main()
35+
#0 %s(%d): main()
3636
#1 {main}
37-
thrown in %s027.php on line 20
37+
thrown in %s on line %d

Zend/tests/match/028.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ try {
3434
usesValue 42
3535
usesValue 42
3636
int(42)
37-
Caught Cannot pass parameter 1 by reference
37+
Caught Test::usesRef(): Argument #1 ($x) cannot be passed by reference

Zend/tests/nullsafe_operator/016.phpt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ test(new Foo());
2929

3030
?>
3131
--EXPECT--
32-
Cannot pass parameter 1 by reference
33-
Cannot pass parameter 1 by reference
34-
Cannot pass parameter 1 by reference
35-
Cannot pass parameter 1 by reference
32+
set(): Argument #1 ($ref) cannot be passed by reference
33+
set(): Argument #1 ($ref) cannot be passed by reference
34+
set(): Argument #1 ($ref) cannot be passed by reference
35+
set(): Argument #1 ($ref) cannot be passed by reference

Zend/tests/variadic/by_ref_error.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ test(1);
99

1010
?>
1111
--EXPECTF--
12-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
12+
Fatal error: Uncaught Error: test(): Argument #1 cannot be passed by reference in %s:%d
1313
Stack trace:
1414
#0 {main}
1515
thrown in %s on line %d

Zend/zend_API.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -319,23 +319,23 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_unexpected_extra_named_error(void)
319319

320320
static ZEND_COLD void ZEND_FASTCALL zend_argument_error_variadic(zend_class_entry *error_ce, uint32_t arg_num, const char *format, va_list va) /* {{{ */
321321
{
322-
const char *space;
323-
const char *class_name;
322+
char *func_name;
324323
const char *arg_name;
325324
char *message = NULL;
326325
if (EG(exception)) {
327326
return;
328327
}
329328

330-
class_name = get_active_class_name(&space);
329+
func_name = get_active_function_or_method_name();
331330
arg_name = get_active_function_arg_name(arg_num);
332331

333332
zend_vspprintf(&message, 0, format, va);
334-
zend_throw_error(error_ce, "%s%s%s(): Argument #%d%s%s%s %s",
335-
class_name, space, get_active_function_name(), arg_num,
333+
zend_throw_error(error_ce, "%s(): Argument #%d%s%s%s %s",
334+
func_name, arg_num,
336335
arg_name ? " ($" : "", arg_name ? arg_name : "", arg_name ? ")" : "", message
337336
);
338337
efree(message);
338+
efree(func_name);
339339
}
340340
/* }}} */
341341

Zend/zend_execute.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,9 +308,13 @@ ZEND_API void ZEND_FASTCALL zend_free_extra_named_params(zend_array *extra_named
308308

309309
/* services */
310310
ZEND_API const char *get_active_class_name(const char **space);
311+
ZEND_API const char *get_class_name(const zend_function *func, const char **space);
311312
ZEND_API const char *get_active_function_name(void);
313+
ZEND_API const char *get_function_name(const zend_function *func);
312314
ZEND_API const char *get_active_function_arg_name(uint32_t arg_num);
313315
ZEND_API const char *get_function_arg_name(const zend_function *func, uint32_t arg_num);
316+
ZEND_API char *get_active_function_or_method_name();
317+
ZEND_API char *get_function_or_method_name(const zend_function *func);
314318
ZEND_API const char *zend_get_executed_filename(void);
315319
ZEND_API zend_string *zend_get_executed_filename_ex(void);
316320
ZEND_API uint32_t zend_get_executed_lineno(void);

Zend/zend_execute_API.c

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -429,16 +429,20 @@ void shutdown_executor(void) /* {{{ */
429429
/* return class name and "::" or "". */
430430
ZEND_API const char *get_active_class_name(const char **space) /* {{{ */
431431
{
432-
zend_function *func;
433-
434432
if (!zend_is_executing()) {
435433
if (space) {
436434
*space = "";
437435
}
438436
return "";
439437
}
440438

441-
func = EG(current_execute_data)->func;
439+
return get_class_name(EG(current_execute_data)->func, space);
440+
}
441+
/* }}} */
442+
443+
/* return class name and "::" or "". */
444+
ZEND_API const char *get_class_name(const zend_function *func, const char **space) /* {{{ */
445+
{
442446
switch (func->type) {
443447
case ZEND_USER_FUNCTION:
444448
case ZEND_INTERNAL_FUNCTION:
@@ -461,12 +465,16 @@ ZEND_API const char *get_active_class_name(const char **space) /* {{{ */
461465

462466
ZEND_API const char *get_active_function_name(void) /* {{{ */
463467
{
464-
zend_function *func;
465-
466468
if (!zend_is_executing()) {
467469
return NULL;
468470
}
469-
func = EG(current_execute_data)->func;
471+
472+
return get_function_name(EG(current_execute_data)->func);
473+
}
474+
/* }}} */
475+
476+
ZEND_API const char *get_function_name(const zend_function *func) /* {{{ */
477+
{
470478
switch (func->type) {
471479
case ZEND_USER_FUNCTION: {
472480
zend_string *function_name = func->common.function_name;
@@ -487,6 +495,29 @@ ZEND_API const char *get_active_function_name(void) /* {{{ */
487495
}
488496
/* }}} */
489497

498+
ZEND_API char *get_active_function_or_method_name(void) /* {{{ */
499+
{
500+
if (!zend_is_executing()) {
501+
return "";
502+
}
503+
504+
return get_function_or_method_name(EG(current_execute_data)->func);
505+
}
506+
/* }}} */
507+
508+
ZEND_API char *get_function_or_method_name(const zend_function *func) /* {{{ */
509+
{
510+
char *name = NULL;
511+
const char *class_name, *space;
512+
513+
class_name = get_class_name(func, &space);
514+
515+
zend_spprintf(&name, 0, "%s%s%s", class_name, space, get_function_name(func));
516+
517+
return name;
518+
}
519+
/* }}} */
520+
490521
ZEND_API const char *get_active_function_arg_name(uint32_t arg_num) /* {{{ */
491522
{
492523
zend_function *func;

Zend/zend_vm_def.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4579,9 +4579,16 @@ ZEND_VM_COLD_HELPER(zend_cannot_pass_by_ref_helper, ANY, ANY)
45794579
USE_OPLINE
45804580
zval *arg;
45814581
uint32_t arg_num = opline->op2.num;
4582+
char *func_name = get_function_or_method_name(EX(call)->func);
4583+
const char *param_name = get_function_arg_name(EX(call)->func, arg_num);
45824584

45834585
SAVE_OPLINE();
4584-
zend_throw_error(NULL, "Cannot pass parameter %d by reference", arg_num);
4586+
4587+
zend_throw_error(NULL, "%s(): Argument #%d%s%s%s cannot be passed by reference",
4588+
func_name, arg_num, param_name ? " ($" : "",
4589+
param_name ? param_name : "", param_name ? ")" : ""
4590+
);
4591+
efree(func_name);
45854592
FREE_OP1();
45864593
arg = ZEND_CALL_VAR(EX(call), opline->result.var);
45874594
ZVAL_UNDEF(arg);

Zend/zend_vm_execute.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1842,9 +1842,16 @@ static zend_never_inline ZEND_COLD ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_ca
18421842
USE_OPLINE
18431843
zval *arg;
18441844
uint32_t arg_num = opline->op2.num;
1845+
char *func_name = get_function_or_method_name(EX(call)->func);
1846+
const char *param_name = get_function_arg_name(EX(call)->func, arg_num);
18451847

18461848
SAVE_OPLINE();
1847-
zend_throw_error(NULL, "Cannot pass parameter %d by reference", arg_num);
1849+
1850+
zend_throw_error(NULL, "%s(): Argument #%d%s%s%s cannot be passed by reference",
1851+
func_name, arg_num, param_name ? " ($" : "",
1852+
param_name ? param_name : "", param_name ? ")" : ""
1853+
);
1854+
efree(func_name);
18481855
FREE_OP(opline->op1_type, opline->op1.var);
18491856
arg = ZEND_CALL_VAR(EX(call), opline->result.var);
18501857
ZVAL_UNDEF(arg);

ext/opcache/jit/zend_jit_disasm_x86.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ static int zend_jit_disasm_init(void)
449449
REGISTER_HELPER(zend_jit_post_dec_typed_ref);
450450
REGISTER_HELPER(zend_jit_assign_op_to_typed_ref);
451451
REGISTER_HELPER(zend_jit_only_vars_by_reference);
452+
REGISTER_HELPER(zend_jit_cannot_pass_by_reference);
452453
REGISTER_HELPER(zend_jit_invalid_array_access);
453454
REGISTER_HELPER(zend_jit_invalid_property_read);
454455
REGISTER_HELPER(zend_jit_invalid_property_write);

ext/opcache/jit/zend_jit_helpers.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1763,6 +1763,18 @@ static void ZEND_FASTCALL zend_jit_only_vars_by_reference(zval *arg)
17631763
zend_error(E_NOTICE, "Only variables should be passed by reference");
17641764
}
17651765

1766+
static void ZEND_FASTCALL zend_jit_cannot_pass_by_reference(uint32_t arg_num)
1767+
{
1768+
const zend_execute_data *execute_data = EG(current_execute_data);
1769+
char *func_name = get_function_or_method_name(EX(call)->func);
1770+
const char *param_name = get_function_arg_name(EX(call)->func, arg_num);
1771+
1772+
zend_throw_error(NULL, "%s(): Argument #%d%s%s%s cannot be passed by reference",
1773+
func_name, arg_num, param_name ? " ($" : "", param_name ? param_name : "", param_name ? ")" : ""
1774+
);
1775+
efree(func_name);
1776+
}
1777+
17661778
static void ZEND_FASTCALL zend_jit_invalid_array_access(zval *container)
17671779
{
17681780
zend_error(E_WARNING, "Trying to access array offset on value of type %s", zend_zval_type_name(container));

ext/opcache/jit/zend_jit_x86.dasc

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1850,20 +1850,8 @@ static int zend_jit_throw_cannot_pass_by_ref_stub(dasm_State **Dst)
18501850
| mov EX->call, RX
18511851
|1:
18521852
| mov RX, r0
1853-
|.if X64
1854-
| xor CARG1, CARG1
1855-
| LOAD_ADDR CARG2, "Cannot pass parameter %d by reference"
1856-
| mov CARG3d, dword OP:r0->op2.num
1857-
| EXT_CALL zend_throw_error, r0
1858-
|.else
1859-
| mov r1, dword OP:r0->op2.num
1860-
| sub r4, 4
1861-
| push r1
1862-
| push "Cannot pass parameter %d by reference"
1863-
| push 0
1864-
| EXT_CALL zend_throw_error, r0
1865-
| add r4, 16
1866-
|.endif
1853+
| mov CARG1d, dword OP:r0->op2.num
1854+
| EXT_CALL zend_jit_cannot_pass_by_reference, r0
18671855
| cmp byte OP:RX->op1_type, IS_TMP_VAR
18681856
| jne >9
18691857
|.if X64

ext/opcache/tests/optimize_func_calls.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ Array
128128
string(7) "changed"
129129
string(7) "changed"
130130

131-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %soptimize_func_calls.php:%d
131+
Fatal error: Uncaught Error: ref(): Argument #1 ($b) cannot be passed by reference in %soptimize_func_calls.php:%d
132132
Stack trace:
133133
#0 {main}
134134
thrown in %soptimize_func_calls.php on line %d

ext/pcre/tests/preg_match_all_error3.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ echo "Done";
1717
--EXPECTF--
1818
*** Testing preg_match_all() : error conditions ***
1919

20-
Fatal error: Uncaught Error: Cannot pass parameter 3 by reference in %s:%d
20+
Fatal error: Uncaught Error: preg_match_all(): Argument #3 ($subpatterns) cannot be passed by reference in %s:%d
2121
Stack trace:
2222
#0 {main}
2323
thrown in %s on line %d

ext/pdo_mysql/tests/bug_37445.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ $stmt = $db->prepare("SELECT 1");
1717
$stmt->bindParam(':a', 'b');
1818
?>
1919
--EXPECTF--
20-
Fatal error: Uncaught Error: Cannot pass parameter 2 by reference in %sbug_37445.php:%d
20+
Fatal error: Uncaught Error: PDOStatement::bindParam(): Argument #2 ($param) cannot be passed by reference in %sbug_37445.php:%d
2121
Stack trace:
2222
#0 {main}
2323
thrown in %sbug_37445.php on line %d

ext/standard/tests/array/array_next_error2.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ function f() {
88
var_dump(next(array(1, 2)));
99
?>
1010
--EXPECTF--
11-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
11+
Fatal error: Uncaught Error: next(): Argument #1 ($arg) cannot be passed by reference in %s:%d
1212
Stack trace:
1313
#0 {main}
1414
thrown in %s on line %d

ext/standard/tests/array/prev_error3.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ prev - ensure we cannot pass a temporary
1010
var_dump(prev(array(1, 2)));
1111
?>
1212
--EXPECTF--
13-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
13+
Fatal error: Uncaught Error: prev(): Argument #1 ($arg) cannot be passed by reference in %s:%d
1414
Stack trace:
1515
#0 {main}
1616
thrown in %s on line %d

tests/classes/constants_error_003.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Basic class support - attempting to pass a class constant by reference.
1616
var_dump(aclass::myConst);
1717
?>
1818
--EXPECTF--
19-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
19+
Fatal error: Uncaught Error: f(): Argument #1 ($a) cannot be passed by reference in %s:%d
2020
Stack trace:
2121
#0 {main}
2222
thrown in %s on line %d

tests/lang/passByReference_002.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ f(2);
1212

1313
?>
1414
--EXPECTF--
15-
Fatal error: Uncaught Error: Cannot pass parameter 1 by reference in %s:%d
15+
Fatal error: Uncaught Error: f(): Argument #1 ($arg1) cannot be passed by reference in %s:%d
1616
Stack trace:
1717
#0 {main}
1818
thrown in %s on line %d

0 commit comments

Comments
 (0)