Skip to content

Fix GH-14082: Segmentation fault on unknown address 0x600000000018 in ext/opcache/jit/zend_jit.c #18916

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions ext/opcache/ZendAccelerator.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@

#ifdef HAVE_JIT
# include "jit/zend_jit.h"
# include "Optimizer/zend_func_info.h"
# include "Optimizer/zend_call_graph.h"
#endif

#ifndef ZEND_WIN32
Expand Down Expand Up @@ -4363,6 +4365,39 @@ static void preload_load(void)
}
}

#if HAVE_JIT
static void zend_accel_clear_call_graph_ptrs(zend_op_array *op_array)
{
ZEND_ASSERT(ZEND_USER_CODE(op_array->type));
zend_func_info *info = ZEND_FUNC_INFO(op_array);
if (info) {
info->caller_info = NULL;
info->callee_info = NULL;
}
}

static void accel_reset_arena_info(zend_persistent_script *script)
{
zend_op_array *op_array;
zend_class_entry *ce;

zend_accel_clear_call_graph_ptrs(&script->script.main_op_array);
ZEND_HASH_MAP_FOREACH_PTR(&script->script.function_table, op_array) {
zend_accel_clear_call_graph_ptrs(op_array);
} ZEND_HASH_FOREACH_END();
ZEND_HASH_MAP_FOREACH_PTR(&script->script.class_table, ce) {
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, op_array) {
if (op_array->scope == ce
&& op_array->type == ZEND_USER_FUNCTION
&& !(op_array->fn_flags & ZEND_ACC_ABSTRACT)
&& !(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
zend_accel_clear_call_graph_ptrs(op_array);
}
} ZEND_HASH_FOREACH_END();
} ZEND_HASH_FOREACH_END();
}
#endif

static zend_result accel_preload(const char *config, bool in_child)
{
zend_file_handle file_handle;
Expand Down Expand Up @@ -4568,6 +4603,18 @@ static zend_result accel_preload(const char *config, bool in_child)
} ZEND_HASH_FOREACH_END();
ZCSG(saved_scripts)[i] = NULL;

#if HAVE_JIT
/* During persisting, the JIT may trigger and fill in the call graph.
* The call graph info is allocated on the arena which will be gone after preloading.
* To prevent invalid accesses during normal requests, the arena data should be cleared.
* This has to be done after all scripts have been persisted because shared op arrays between
* scripts can change the call graph. */
accel_reset_arena_info(ZCSG(preload_script));
for (zend_persistent_script **scripts = ZCSG(saved_scripts); *scripts; scripts++) {
accel_reset_arena_info(*scripts);
}
#endif

zend_shared_alloc_save_state();
accel_interned_strings_save_state();

Expand Down
23 changes: 23 additions & 0 deletions ext/opcache/tests/jit/gh14082.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
GH-14082 (Segmentation fault on unknown address 0x600000000018 in ext/opcache/jit/zend_jit.c)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.jit=1235
opcache.jit_buffer_size=16M
opcache.preload={PWD}/preload_gh14082.inc
--EXTENSIONS--
opcache
--SKIPIF--
<?php
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows');
?>
--FILE--
<?php
Foo::test();
echo "ok\n";
?>
--EXPECT--
int(1)
int(1)
ok
9 changes: 9 additions & 0 deletions ext/opcache/tests/jit/preload_gh14082.inc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
class Foo {
public static function test() {
static $i = 0;
var_dump(++$i);
}
}

Foo::test();
Loading