1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Fix GH-16799: Assertion failure at Zend/zend_vm_execute.h:7469

zend_is_callable_ex() can unfortunately emit a deprecation, and then
a user error handler can throw an exception. This causes an assert
failure at ZEND_VM_NEXT_OPCODE(). We fix this by checking if there's an
exception after zend_is_callable_ex().

Closes GH-16803.
This commit is contained in:
Niels Dossche
2024-11-14 22:01:47 +01:00
parent f725f504e8
commit 553d79c709
4 changed files with 63 additions and 0 deletions

2
NEWS
View File

@@ -9,6 +9,8 @@ PHP NEWS
. Fail early in *nix configuration build script. (hakre)
. Fixed bug GH-16727 (Opcache bad signal 139 crash in ZTS bookworm
(frankenphp)). (nielsdos)
. Fixed bug GH-16799 (Assertion failure at Zend/zend_vm_execute.h:7469).
(nielsdos)
- FPM:
. Fixed GH-16432 (PHP-FPM 8.2 SIGSEGV in fpm_get_status). (Jakub Zelenka)

21
Zend/tests/gh16799.phpt Normal file
View File

@@ -0,0 +1,21 @@
--TEST--
GH-16799 (Assertion failure at Zend/zend_vm_execute.h)
--FILE--
<?php
set_error_handler(function($_, $m) { throw new Exception($m); });
class Test {
static function test() {
call_user_func("static::ok");
}
static function ok() {
}
}
Test::test();
?>
--EXPECTF--
Fatal error: Uncaught Exception: Use of "static" in callables is deprecated in %s:%d
Stack trace:
#0 %s(%d): {closure}(%d, 'Use of "static"...', %s, %d)
#1 %s(%d): Test::test()
#2 {main}
thrown in %s on line %d

View File

@@ -3807,6 +3807,16 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM)
function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
ZEND_ASSERT(!error);
/* Deprecation can be emitted from zend_is_callable_ex(), which can
* invoke a user error handler and throw an exception.
* For the CONST and CV case we reuse the same exception block below
* to make sure we don't increase VM size too much. */
if (!(OP2_TYPE & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
FREE_OP2();
HANDLE_EXCEPTION();
}
func = fcc.function_handler;
object_or_called_scope = fcc.called_scope;
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {

30
Zend/zend_vm_execute.h generated
View File

@@ -7023,6 +7023,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
function_name = RT_CONSTANT(opline, opline->op2);
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
ZEND_ASSERT(!error);
/* Deprecation can be emitted from zend_is_callable_ex(), which can
* invoke a user error handler and throw an exception.
* For the CONST and CV case we reuse the same exception block below
* to make sure we don't increase VM size too much. */
if (!(IS_CONST & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
HANDLE_EXCEPTION();
}
func = fcc.function_handler;
object_or_called_scope = fcc.called_scope;
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
@@ -9368,6 +9378,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
function_name = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC);
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
ZEND_ASSERT(!error);
/* Deprecation can be emitted from zend_is_callable_ex(), which can
* invoke a user error handler and throw an exception.
* For the CONST and CV case we reuse the same exception block below
* to make sure we don't increase VM size too much. */
if (!((IS_TMP_VAR|IS_VAR) & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
zval_ptr_dtor_nogc(EX_VAR(opline->op2.var));
HANDLE_EXCEPTION();
}
func = fcc.function_handler;
object_or_called_scope = fcc.called_scope;
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
@@ -11742,6 +11762,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H
function_name = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC);
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
ZEND_ASSERT(!error);
/* Deprecation can be emitted from zend_is_callable_ex(), which can
* invoke a user error handler and throw an exception.
* For the CONST and CV case we reuse the same exception block below
* to make sure we don't increase VM size too much. */
if (!(IS_CV & (IS_TMP_VAR|IS_VAR)) && UNEXPECTED(EG(exception))) {
HANDLE_EXCEPTION();
}
func = fcc.function_handler;
object_or_called_scope = fcc.called_scope;
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {