Skip to content

Commit

Permalink
Create reference wrappers in SEND_UNPACK if necessary
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
nikic committed Sep 30, 2021
1 parent d0860f6 commit e11faad
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 10 deletions.
18 changes: 18 additions & 0 deletions Zend/tests/unpack_iterator_by_ref_type_check.phpt
@@ -0,0 +1,18 @@
--TEST--
Unpack iterator by reference with type check
--FILE--
<?php
function test(T &$a) {
}
function gen() {
yield null;
}
try {
test(...gen());
} catch (TypeError $e) {
echo $e->getMessage(), "\n";
}
?>
--EXPECTF--
Warning: Cannot pass by-reference argument 1 of test() by unpacking a Traversable, passing by-value instead in %s on line %d
test(): Argument #1 ($a) must be of type T, null given, called in %s on line %d
19 changes: 14 additions & 5 deletions Zend/zend_vm_def.h
Expand Up @@ -5126,6 +5126,9 @@ ZEND_VM_C_LABEL(send_again):
break;
}

ZVAL_DEREF(arg);
Z_TRY_ADDREF_P(arg);

if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
zend_error(
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
Expand All @@ -5134,9 +5137,11 @@ ZEND_VM_C_LABEL(send_again):
EX(call)->func->common.scope ? "::" : "",
ZSTR_VAL(EX(call)->func->common.function_name)
);
ZVAL_NEW_REF(top, arg);
} else {
ZVAL_COPY_VALUE(top, arg);
}

ZVAL_COPY_DEREF(top, arg);
zend_string_release(name);
} else {
if (have_named_params) {
Expand All @@ -5145,6 +5150,11 @@ ZEND_VM_C_LABEL(send_again):
break;
}

zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
top = ZEND_CALL_ARG(EX(call), arg_num);
ZVAL_DEREF(arg);
Z_TRY_ADDREF_P(arg);

if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
zend_error(
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
Expand All @@ -5153,12 +5163,11 @@ ZEND_VM_C_LABEL(send_again):
EX(call)->func->common.scope ? "::" : "",
ZSTR_VAL(EX(call)->func->common.function_name)
);
ZVAL_NEW_REF(top, arg);
} else {
ZVAL_COPY_VALUE(top, arg);
}


zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
top = ZEND_CALL_ARG(EX(call), arg_num);
ZVAL_COPY_DEREF(top, arg);
ZEND_CALL_NUM_ARGS(EX(call))++;
}

Expand Down
19 changes: 14 additions & 5 deletions Zend/zend_vm_execute.h
Expand Up @@ -2248,6 +2248,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
break;
}

ZVAL_DEREF(arg);
Z_TRY_ADDREF_P(arg);

if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
zend_error(
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
Expand All @@ -2256,9 +2259,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
EX(call)->func->common.scope ? "::" : "",
ZSTR_VAL(EX(call)->func->common.function_name)
);
ZVAL_NEW_REF(top, arg);
} else {
ZVAL_COPY_VALUE(top, arg);
}

ZVAL_COPY_DEREF(top, arg);
zend_string_release(name);
} else {
if (have_named_params) {
Expand All @@ -2267,6 +2272,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
break;
}

zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
top = ZEND_CALL_ARG(EX(call), arg_num);
ZVAL_DEREF(arg);
Z_TRY_ADDREF_P(arg);

if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
zend_error(
E_WARNING, "Cannot pass by-reference argument %d of %s%s%s()"
Expand All @@ -2275,12 +2285,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
EX(call)->func->common.scope ? "::" : "",
ZSTR_VAL(EX(call)->func->common.function_name)
);
ZVAL_NEW_REF(top, arg);
} else {
ZVAL_COPY_VALUE(top, arg);
}


zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
top = ZEND_CALL_ARG(EX(call), arg_num);
ZVAL_COPY_DEREF(top, arg);
ZEND_CALL_NUM_ARGS(EX(call))++;
}

Expand Down

0 comments on commit e11faad

Please sign in to comment.