Skip to content

Commit b5b0040

Browse files
committed
ext/opcache: unwrap reference wrappers in typed by-value returns
1 parent 0173ef4 commit b5b0040

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
@@ -89,6 +89,8 @@ PHP NEWS
8989
. Added mysqli_quote_string() and mysqli::quote_string(). (Kamil Tekiela)
9090

9191
- Opcache:
92+
. Fixed bug GH-21972 (Corrupted variable type when a typed by-value return
93+
contains a reference wrapper). (Weilin Du)
9294
. Fixed bug GH-20051 (apache2 shutdowns when restart is requested during
9395
preloading). (Arnaud, welcomycozyhom)
9496

Zend/zend_vm_def.h

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

4494-
if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(retval_ptr)))) {
4495-
ZEND_VM_NEXT_OPCODE();
4496-
}
4497-
4498-
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
4499-
SAVE_OPLINE();
4500-
retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
4501-
if (UNEXPECTED(EG(exception))) {
4502-
HANDLE_EXCEPTION();
4503-
}
4504-
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
4505-
ZEND_VM_NEXT_OPCODE();
4506-
}
4507-
}
4508-
45094494
zend_reference *ref = NULL;
45104495
if (UNEXPECTED(retval_ref != retval_ptr)) {
45114496
if (UNEXPECTED(EX(func)->op_array.fn_flags & ZEND_ACC_RETURN_REFERENCE)) {
@@ -4522,6 +4507,21 @@ ZEND_VM_COLD_CONST_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV
45224507
}
45234508
}
45244509

4510+
if (EXPECTED(ZEND_TYPE_CONTAINS_CODE(ret_info->type, Z_TYPE_P(retval_ptr)))) {
4511+
ZEND_VM_NEXT_OPCODE();
4512+
}
4513+
4514+
if (OP1_TYPE == IS_CV && UNEXPECTED(Z_ISUNDEF_P(retval_ptr))) {
4515+
SAVE_OPLINE();
4516+
retval_ref = retval_ptr = ZVAL_UNDEFINED_OP1();
4517+
if (UNEXPECTED(EG(exception))) {
4518+
HANDLE_EXCEPTION();
4519+
}
4520+
if (ZEND_TYPE_FULL_MASK(ret_info->type) & MAY_BE_NULL) {
4521+
ZEND_VM_NEXT_OPCODE();
4522+
}
4523+
}
4524+
45254525
SAVE_OPLINE();
45264526
if (UNEXPECTED(!zend_check_type_slow(&ret_info->type, retval_ptr, ref, 1, 0))) {
45274527
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)