From daba40c695b24b0b2bdde0ba6227d06d666d85e3 Mon Sep 17 00:00:00 2001 From: Niels Dossche <7771979+nielsdos@users.noreply.github.com> Date: Mon, 23 Sep 2024 20:11:02 +0200 Subject: [PATCH] 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. --- NEWS | 3 +++ ext/opcache/jit/zend_jit_ir.c | 30 ++++++++++++++++++++++++------ ext/opcache/tests/jit/gh16009.phpt | 22 ++++++++++++++++++++++ 3 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 ext/opcache/tests/jit/gh16009.phpt diff --git a/NEWS b/NEWS index d0e459b2b87..0f6b6c9c520 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.4.0RC2 +- Opcache: + . Fixed bug GH-16009 (Segmentation fault with frameless functions and + undefined CVs). (nielsdos) 26 Sep 2024, PHP 8.4.0RC1 diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 38ee5c409c3..c3ab026deec 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -17224,7 +17224,10 @@ static void jit_frameless_icall1(zend_jit_ctx *jit, const zend_op *opline, uint3 ir_ref op1_ref = jit_ZVAL_ADDR(jit, op1_addr); jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) { - zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); + op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); + op1_info &= ~MAY_BE_UNDEF; + op1_info |= MAY_BE_NULL; + op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref); } if (op1_info & MAY_BE_REF) { 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 ir_ref op2_ref = jit_ZVAL_ADDR(jit, op2_addr); jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) { - zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); + op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); + op1_info &= ~MAY_BE_UNDEF; + op1_info |= MAY_BE_NULL; + op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref); } if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) { - zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1); + op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1); + op2_info &= ~MAY_BE_UNDEF; + op2_info |= MAY_BE_NULL; + op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref); } if (op1_info & MAY_BE_REF) { 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 ir_ref op3_ref = jit_ZVAL_ADDR(jit, op3_addr); jit_set_Z_TYPE_INFO(jit, res_addr, IS_NULL); if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) { - zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); + op1_ref = zend_jit_zval_check_undef(jit, op1_ref, opline->op1.var, opline, 1); + op1_info &= ~MAY_BE_UNDEF; + op1_info |= MAY_BE_NULL; + op1_addr = ZEND_ADDR_REF_ZVAL(op1_ref); } if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) { - zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1); + op2_ref = zend_jit_zval_check_undef(jit, op2_ref, opline->op2.var, opline, 1); + op2_info &= ~MAY_BE_UNDEF; + op2_info |= MAY_BE_NULL; + op2_addr = ZEND_ADDR_REF_ZVAL(op2_ref); } if ((opline+1)->op1_type == IS_CV && (op1_data_info & MAY_BE_UNDEF)) { - zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1); + op3_ref = zend_jit_zval_check_undef(jit, op3_ref, (opline+1)->op1.var, opline, 1); + op1_data_info &= ~MAY_BE_UNDEF; + op1_data_info |= MAY_BE_NULL; + op3_addr = ZEND_ADDR_REF_ZVAL(op3_ref); } if (op1_info & MAY_BE_REF) { op1_ref = jit_ZVAL_DEREF_ref(jit, op1_ref); diff --git a/ext/opcache/tests/jit/gh16009.phpt b/ext/opcache/tests/jit/gh16009.phpt new file mode 100644 index 00000000000..6c1d6b6984d --- /dev/null +++ b/ext/opcache/tests/jit/gh16009.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-16009 (Segmentation fault with frameless functions and undefined CVs) +--EXTENSIONS-- +opcache +--INI-- +opcache.jit=1012 +--FILE-- + +--EXPECTF-- +Warning: Undefined variable $value in %s on line %d + +Fatal error: Uncaught TypeError: testMin2Second(): Return value must be of type int, null returned in %s:%d +Stack trace: +#0 %s(%d): testMin2Second() +#1 {main} + thrown in %s on line %d