mirror of
https://github.com/php/php-src.git
synced 2024-12-14 04:16:30 +08:00
Merge branch 'PHP-8.2'
* PHP-8.2: Fix GH-11245 (In some specific cases SWITCH with one default statement will cause segfault)
This commit is contained in:
commit
24ff7eee3f
@ -264,6 +264,10 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case ZEND_FREE:
|
case ZEND_FREE:
|
||||||
|
/* Note: Only remove the source if the source is local to this block.
|
||||||
|
* If it's not local, then the other blocks successors must also eventually either FREE or consume the temporary,
|
||||||
|
* hence removing the temporary is not safe in the general case, especially when other consumers are not FREE.
|
||||||
|
* A FREE may not be removed without also removing the source's result, because otherwise that would cause a memory leak. */
|
||||||
if (opline->op1_type == IS_TMP_VAR) {
|
if (opline->op1_type == IS_TMP_VAR) {
|
||||||
src = VAR_SOURCE(opline->op1);
|
src = VAR_SOURCE(opline->op1);
|
||||||
if (src) {
|
if (src) {
|
||||||
@ -272,6 +276,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
|
|||||||
case ZEND_BOOL_NOT:
|
case ZEND_BOOL_NOT:
|
||||||
/* T = BOOL(X), FREE(T) => T = BOOL(X) */
|
/* T = BOOL(X), FREE(T) => T = BOOL(X) */
|
||||||
/* The remaining BOOL is removed by a separate optimization */
|
/* The remaining BOOL is removed by a separate optimization */
|
||||||
|
/* The source is a bool, no source removals take place, so this may be done non-locally. */
|
||||||
VAR_SOURCE(opline->op1) = NULL;
|
VAR_SOURCE(opline->op1) = NULL;
|
||||||
MAKE_NOP(opline);
|
MAKE_NOP(opline);
|
||||||
++(*opt_count);
|
++(*opt_count);
|
||||||
@ -290,6 +295,9 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
|
|||||||
case ZEND_PRE_DEC_OBJ:
|
case ZEND_PRE_DEC_OBJ:
|
||||||
case ZEND_PRE_INC_STATIC_PROP:
|
case ZEND_PRE_INC_STATIC_PROP:
|
||||||
case ZEND_PRE_DEC_STATIC_PROP:
|
case ZEND_PRE_DEC_STATIC_PROP:
|
||||||
|
if (src < op_array->opcodes + block->start) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
src->result_type = IS_UNUSED;
|
src->result_type = IS_UNUSED;
|
||||||
VAR_SOURCE(opline->op1) = NULL;
|
VAR_SOURCE(opline->op1) = NULL;
|
||||||
MAKE_NOP(opline);
|
MAKE_NOP(opline);
|
||||||
@ -302,7 +310,7 @@ static void zend_optimize_block(zend_basic_block *block, zend_op_array *op_array
|
|||||||
} else if (opline->op1_type == IS_VAR) {
|
} else if (opline->op1_type == IS_VAR) {
|
||||||
src = VAR_SOURCE(opline->op1);
|
src = VAR_SOURCE(opline->op1);
|
||||||
/* V = OP, FREE(V) => OP. NOP */
|
/* V = OP, FREE(V) => OP. NOP */
|
||||||
if (src &&
|
if (src >= op_array->opcodes + block->start &&
|
||||||
src->opcode != ZEND_FETCH_R &&
|
src->opcode != ZEND_FETCH_R &&
|
||||||
src->opcode != ZEND_FETCH_STATIC_PROP_R &&
|
src->opcode != ZEND_FETCH_STATIC_PROP_R &&
|
||||||
src->opcode != ZEND_FETCH_DIM_R &&
|
src->opcode != ZEND_FETCH_DIM_R &&
|
||||||
|
33
ext/opcache/tests/opt/gh11245_1.phpt
Normal file
33
ext/opcache/tests/opt/gh11245_1.phpt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
--TEST--
|
||||||
|
GH-11245: In some specific cases SWITCH with one default statement will cause segfault (VAR variation)
|
||||||
|
--INI--
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.optimization_level=0x7FFFBFFF
|
||||||
|
opcache.opt_debug_level=0x20000
|
||||||
|
opcache.preload=
|
||||||
|
--EXTENSIONS--
|
||||||
|
opcache
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
function xx() { return "somegarbage"; }
|
||||||
|
switch (xx()) {
|
||||||
|
default:
|
||||||
|
if (!empty($xx)) {return;}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
$_main:
|
||||||
|
; (lines=4, args=0, vars=1, tmps=1)
|
||||||
|
; (after optimizer)
|
||||||
|
; %s
|
||||||
|
0000 T1 = ISSET_ISEMPTY_CV (empty) CV0($xx)
|
||||||
|
0001 JMPNZ T1 0003
|
||||||
|
0002 RETURN null
|
||||||
|
0003 RETURN int(1)
|
||||||
|
|
||||||
|
xx:
|
||||||
|
; (lines=1, args=0, vars=0, tmps=0)
|
||||||
|
; (after optimizer)
|
||||||
|
; %s
|
||||||
|
0000 RETURN string("somegarbage")
|
35
ext/opcache/tests/opt/gh11245_2.phpt
Normal file
35
ext/opcache/tests/opt/gh11245_2.phpt
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
--TEST--
|
||||||
|
GH-11245: In some specific cases SWITCH with one default statement will cause segfault (TMP variation)
|
||||||
|
--INI--
|
||||||
|
opcache.enable=1
|
||||||
|
opcache.enable_cli=1
|
||||||
|
opcache.optimization_level=0x7FFFBFFF
|
||||||
|
opcache.opt_debug_level=0x20000
|
||||||
|
opcache.preload=
|
||||||
|
--EXTENSIONS--
|
||||||
|
opcache
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class X {
|
||||||
|
// Chosen to test for a memory leak.
|
||||||
|
static $prop = "aa";
|
||||||
|
}
|
||||||
|
switch (++X::$prop) {
|
||||||
|
default:
|
||||||
|
if (empty($xx)) {return;}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
$_main:
|
||||||
|
; (lines=7, args=0, vars=1, tmps=2)
|
||||||
|
; (after optimizer)
|
||||||
|
; %s
|
||||||
|
0000 T1 = PRE_INC_STATIC_PROP string("prop") string("X")
|
||||||
|
0001 T2 = ISSET_ISEMPTY_CV (empty) CV0($xx)
|
||||||
|
0002 JMPZ T2 0005
|
||||||
|
0003 FREE T1
|
||||||
|
0004 RETURN null
|
||||||
|
0005 FREE T1
|
||||||
|
0006 RETURN int(1)
|
||||||
|
LIVE RANGES:
|
||||||
|
1: 0001 - 0005 (tmp/var)
|
Loading…
Reference in New Issue
Block a user