Skip to content

Commit daba40c

Browse files
committed
Fix GH-16009: Segmentation fault with frameless functions and undefined CVs
The frameless function handlers do not update the op variables when handling the result is undefined. In this case this causes propagating an UNDEF value into a temporary, which results in an extra undefined variable warning for a temporary in this case. The original issue also reports a crash in some cases, which is also fixed by this patch. Closes GH-16012.
1 parent 7225a11 commit daba40c

File tree

3 files changed

+49
-6
lines changed

3 files changed

+49
-6
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.0RC2
44

5+
- Opcache:
6+
. Fixed bug GH-16009 (Segmentation fault with frameless functions and
7+
undefined CVs). (nielsdos)
58

69
26 Sep 2024, PHP 8.4.0RC1
710

ext/opcache/jit/zend_jit_ir.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17224,7 +17224,10 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint3
1722417224
ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr);
1722517225
jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
1722617226
if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17227-
zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17227+
op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17228+
op1_info &= ~MAY_BE_UNDEF;
17229+
op1_info |= MAY_BE_NULL;
17230+
op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
1722817231
}
1722917232
if (op1_info & MAY_BE_REF) {
1723017233
op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
@@ -17266,10 +17269,16 @@ static void jit_frameless_icall2(zend_jit_ctx *jit, const zend_op *opline, uint3
1726617269
ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr);
1726717270
jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
1726817271
if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17269-
zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17272+
op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17273+
op1_info &= ~MAY_BE_UNDEF;
17274+
op1_info |= MAY_BE_NULL;
17275+
op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
1727017276
}
1727117277
if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17272-
zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17278+
op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17279+
op2_info &= ~MAY_BE_UNDEF;
17280+
op2_info |= MAY_BE_NULL;
17281+
op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
1727317282
}
1727417283
if (op1_info & MAY_BE_REF) {
1727517284
op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);
@@ -17325,13 +17334,22 @@ static void jit_frameless_icall3(zend_jit_ctx *jit, const zend_op *opline, uint3
1732517334
ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr);
1732617335
jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL);
1732717336
if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) {
17328-
zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17337+
op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1);
17338+
op1_info &= ~MAY_BE_UNDEF;
17339+
op1_info |= MAY_BE_NULL;
17340+
op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref);
1732917341
}
1733017342
if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) {
17331-
zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17343+
op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1);
17344+
op2_info &= ~MAY_BE_UNDEF;
17345+
op2_info |= MAY_BE_NULL;
17346+
op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref);
1733217347
}
1733317348
if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) {
17334-
zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1);
17349+
op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1);
17350+
op1_data_info &= ~MAY_BE_UNDEF;
17351+
op1_data_info |= MAY_BE_NULL;
17352+
op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref);
1733517353
}
1733617354
if (op1_info & MAY_BE_REF) {
1733717355
op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref);

ext/opcache/tests/jit/gh16009.phpt

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
GH-16009 (Segmentation fault with frameless functions and undefined CVs)
3+
--EXTENSIONS--
4+
opcache
5+
--INI--
6+
opcache.jit=1012
7+
--FILE--
8+
<?php
9+
function testMin2Second(): int {
10+
$value = min(100, $value);
11+
return $value;
12+
}
13+
testMin2Second();
14+
?>
15+
--EXPECTF--
16+
Warning: Undefined variable $value in %s on line %d
17+
18+
Fatal error: Uncaught TypeError: testMin2Second(): Return value must be of type int, null returned in %s:%d
19+
Stack trace:
20+
#0 %s(%d): testMin2Second()
21+
#1 {main}
22+
thrown in %s on line %d

0 commit comments

Comments
 (0)