Skip to content

Commit e11faad

Browse files
committed
Create reference wrappers in SEND_UNPACK if necessary
Even if we can't actually pass by reference, we still need to create the REFERENCE wrapper to satisfy the calling convention. The particular test case would crash with JIT, because the existence of the reference was assumed. Fixes oss-fuzz #39440.
1 parent d0860f6 commit e11faad

File tree

3 files changed

+46
-10
lines changed

3 files changed

+46
-10
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Unpack iterator by reference with type check
3+
--FILE--
4+
<?php
5+
function test(T &$a) {
6+
}
7+
function gen() {
8+
yield null;
9+
}
10+
try {
11+
test(...gen());
12+
} catch (TypeError $e) {
13+
echo $e->getMessage(), "\n";
14+
}
15+
?>
16+
--EXPECTF--
17+
Warning: Cannot pass by-reference argument 1 of test() by unpacking a Traversable, passing by-value instead in %s on line %d
18+
test(): Argument #1 ($a) must be of type T, null given, called in %s on line %d

Zend/zend_vm_def.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5126,6 +5126,9 @@ ZEND_VM_C_LABEL(send_again):
51265126
break;
51275127
}
51285128

5129+
ZVAL_DEREF(arg);
5130+
Z_TRY_ADDREF_P(arg);
5131+
51295132
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
51305133
zend_error(
51315134
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
@@ -5134,9 +5137,11 @@ ZEND_VM_C_LABEL(send_again):
51345137
EX(call)->func->common.scope ? "::" : "",
51355138
ZSTR_VAL(EX(call)->func->common.function_name)
51365139
);
5140+
ZVAL_NEW_REF(top, arg);
5141+
} else {
5142+
ZVAL_COPY_VALUE(top, arg);
51375143
}
51385144

5139-
ZVAL_COPY_DEREF(top, arg);
51405145
zend_string_release(name);
51415146
} else {
51425147
if (have_named_params) {
@@ -5145,6 +5150,11 @@ ZEND_VM_C_LABEL(send_again):
51455150
break;
51465151
}
51475152

5153+
zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
5154+
top = ZEND_CALL_ARG(EX(call), arg_num);
5155+
ZVAL_DEREF(arg);
5156+
Z_TRY_ADDREF_P(arg);
5157+
51485158
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
51495159
zend_error(
51505160
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
@@ -5153,12 +5163,11 @@ ZEND_VM_C_LABEL(send_again):
51535163
EX(call)->func->common.scope ? "::" : "",
51545164
ZSTR_VAL(EX(call)->func->common.function_name)
51555165
);
5166+
ZVAL_NEW_REF(top, arg);
5167+
} else {
5168+
ZVAL_COPY_VALUE(top, arg);
51565169
}
51575170

5158-
5159-
zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
5160-
top = ZEND_CALL_ARG(EX(call), arg_num);
5161-
ZVAL_COPY_DEREF(top, arg);
51625171
ZEND_CALL_NUM_ARGS(EX(call))++;
51635172
}
51645173

Zend/zend_vm_execute.h

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,6 +2248,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
22482248
break;
22492249
}
22502250

2251+
ZVAL_DEREF(arg);
2252+
Z_TRY_ADDREF_P(arg);
2253+
22512254
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
22522255
zend_error(
22532256
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
@@ -2256,9 +2259,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
22562259
EX(call)->func->common.scope ? "::" : "",
22572260
ZSTR_VAL(EX(call)->func->common.function_name)
22582261
);
2262+
ZVAL_NEW_REF(top, arg);
2263+
} else {
2264+
ZVAL_COPY_VALUE(top, arg);
22592265
}
22602266

2261-
ZVAL_COPY_DEREF(top, arg);
22622267
zend_string_release(name);
22632268
} else {
22642269
if (have_named_params) {
@@ -2267,6 +2272,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
22672272
break;
22682273
}
22692274

2275+
zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
2276+
top = ZEND_CALL_ARG(EX(call), arg_num);
2277+
ZVAL_DEREF(arg);
2278+
Z_TRY_ADDREF_P(arg);
2279+
22702280
if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
22712281
zend_error(
22722282
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
@@ -2275,12 +2285,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
22752285
EX(call)->func->common.scope ? "::" : "",
22762286
ZSTR_VAL(EX(call)->func->common.function_name)
22772287
);
2288+
ZVAL_NEW_REF(top, arg);
2289+
} else {
2290+
ZVAL_COPY_VALUE(top, arg);
22782291
}
22792292

2280-
2281-
zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
2282-
top = ZEND_CALL_ARG(EX(call), arg_num);
2283-
ZVAL_COPY_DEREF(top, arg);
22842293
ZEND_CALL_NUM_ARGS(EX(call))++;
22852294
}
22862295

0 commit comments

Comments
 (0)