Skip to content

Commit

Permalink
Fixed bug #75786
Browse files Browse the repository at this point in the history
SEND_UNPACK on iterators was duplicating references in-place,
which effectively leaks the original value and causes an off-by-one
refcount on the duplicated value.

Replace this with a deref, as an actual duplication is not even
needed in this case.
  • Loading branch information
nikic committed Jan 9, 2018
1 parent f208187 commit fd30c59
Show file tree
Hide file tree
Showing 4 changed files with 24 additions and 10 deletions.
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ PHP NEWS

- Core:
. Fixed bug #75679 (Path 260 character problem). (Anatol)
. Fixed bug #75786 (segfault when using spread operator on generator passed
by reference). (Nikita)

- Opcache:
. Fixed bug #75720 (File cache not populated after SHM runs full). (Dmitry)
Expand Down
18 changes: 18 additions & 0 deletions Zend/tests/bug75786.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Bug #75786: segfault when using spread operator on generator passed by reference
--FILE--
<?php

function &gen($items) {
foreach ($items as $key => &$value) {
yield $key => $value;
}
}

var_dump(...gen(['a', 'b', 'c']));

?>
--EXPECT--
string(1) "a"
string(1) "b"
string(1) "c"
7 changes: 2 additions & 5 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -4647,11 +4647,8 @@ ZEND_VM_C_LABEL(send_again):
);
}

if (Z_ISREF_P(arg)) {
ZVAL_DUP(arg, Z_REFVAL_P(arg));
} else {
if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg);
}
ZVAL_DEREF(arg);
Z_TRY_ADDREF_P(arg);

zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
top = ZEND_CALL_ARG(EX(call), arg_num);
Expand Down
7 changes: 2 additions & 5 deletions Zend/zend_vm_execute.h
Original file line number Diff line number Diff line change
Expand Up @@ -1358,11 +1358,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_
);
}

if (Z_ISREF_P(arg)) {
ZVAL_DUP(arg, Z_REFVAL_P(arg));
} else {
if (Z_REFCOUNTED_P(arg)) Z_ADDREF_P(arg);
}
ZVAL_DEREF(arg);
Z_TRY_ADDREF_P(arg);

zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, 1);
top = ZEND_CALL_ARG(EX(call), arg_num);
Expand Down

0 comments on commit fd30c59

Please sign in to comment.