Skip to content

Commit e3a7ece

Browse files
committed
ext/opcache: unwrap reference wrappers in typed by-value returns
1 parent 14f2071 commit e3a7ece

3 files changed

Lines changed: 56 additions & 15 deletions

File tree

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ PHP NEWS
66
. Fix persistent free of non-persistent connect_attr key (David Carlier).
77

88
- Opcache:
9+
. Fixed bug GH-21972 (Corrupted variable type when a typed by-value return
10+
contains a reference wrapper). (Weilin Du)
911
. Fixed tracing JIT crash when a VM interrupt is handled during an observed
1012
user function call. (Levi Morrison)
1113

Zend/zend_vm_def.h

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4387,21 +4387,6 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
43874387
ZVAL_DEREF(retval_ptr);
43884388
}
43894389

4390-
if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(retval_ptr)))) {
4391-
ZEND_VM_NEXT_OPCODE();
4392-
}
4393-
4394-
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
4395-
SAVE_OPLINE();
4396-
retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
4397-
if (UNEXPECTED(EG(exception))) {
4398-
HANDLE_EXCEPTION();
4399-
}
4400-
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
4401-
ZEND_VM_NEXT_OPCODE();
4402-
}
4403-
}
4404-
44054390
zend_reference *ref = NULL;
44064391
void *cache_slot = CACHE_ADDR(opline->op2.num);
44074392
if (UNEXPECTED(retval_ref != retval_ptr)) {
@@ -4419,6 +4404,21 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
44194404
}
44204405
}
44214406

4407+
if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(retval_ptr)))) {
4408+
ZEND_VM_NEXT_OPCODE();
4409+
}
4410+
4411+
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
4412+
SAVE_OPLINE();
4413+
retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
4414+
if (UNEXPECTED(EG(exception))) {
4415+
HANDLE_EXCEPTION();
4416+
}
4417+
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
4418+
ZEND_VM_NEXT_OPCODE();
4419+
}
4420+
}
4421+
44224422
SAVE_OPLINE();
44234423
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, cache_slot, 1, 0))) {
44244424
zend_verify_return_error(EX(func), retval_ptr);

ext/opcache/tests/opt/gh21972.phpt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
--TEST--
2+
GH-21972: Typed by-value return must not leak reference wrapper
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.optimization_level=-1
7+
--EXTENSIONS--
8+
opcache
9+
--FILE--
10+
<?php
11+
declare(strict_types=1);
12+
13+
enum ValueType {
14+
case BOOL;
15+
case MIXED;
16+
}
17+
18+
function applyDefinition(
19+
bool &$lazy = false,
20+
ValueType &$type = ValueType::MIXED,
21+
int &$flags = 0,
22+
?string &$default = null,
23+
): void {
24+
}
25+
26+
function getTypedValue(string $default, bool $lazy, ValueType $type): string {
27+
applyDefinition($lazy, $type, default: $default);
28+
return $default;
29+
}
30+
31+
$value = getTypedValue('false', false, ValueType::BOOL);
32+
var_dump(gettype($value));
33+
var_dump(strtolower($value));
34+
var_dump(strtolower(getTypedValue('FALSE', false, ValueType::BOOL)));
35+
?>
36+
--EXPECT--
37+
string(6) "string"
38+
string(5) "false"
39+
string(5) "false"

0 commit comments

Comments
 (0)