-
Notifications
You must be signed in to change notification settings - Fork 7.8k
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
Fix GH-17715: Handle preloaded internal function runtime cache #17835
base: PHP-8.4
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -70,6 +70,9 @@ typedef struct _zend_string zend_string; | |
} while (0) | ||
# define ZEND_MAP_PTR_BIASED_BASE(real_base) \ | ||
((void*)(((uintptr_t)(real_base)) + zend_map_ptr_static_size * sizeof(void *) - 1)) | ||
// Note: chunked like: [8192..12287][4096..8191][0..4095] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Normally we use C-style comments |
||
#define ZEND_MAP_PTR_STATIC_NUM_TO_PTR(num) \ | ||
((void **)CG(map_ptr_real_base) + zend_map_ptr_static_size - ZEND_MM_ALIGNED_SIZE_EX((num) + 1, 4096) + ((num) & 4095)) | ||
#else | ||
# error "Unknown ZEND_MAP_PTR_KIND" | ||
#endif | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2609,6 +2609,7 @@ static void zend_reset_cache_vars(void) | |
ZCSG(restart_pending) = false; | ||
ZCSG(force_restart_time) = 0; | ||
ZCSG(map_ptr_last) = CG(map_ptr_last); | ||
ZCSG(map_ptr_static_last) = zend_map_ptr_static_last; | ||
} | ||
|
||
static void accel_reset_pcre_cache(void) | ||
|
@@ -2624,7 +2625,7 @@ static void accel_reset_pcre_cache(void) | |
} ZEND_HASH_FOREACH_END(); | ||
} | ||
|
||
zend_result accel_activate(INIT_FUNC_ARGS) | ||
ZEND_RINIT_FUNCTION(zend_accelerator) | ||
{ | ||
if (!ZCG(enabled) || !accel_startup_ok) { | ||
ZCG(accelerator_enabled) = false; | ||
|
@@ -2956,12 +2957,15 @@ static void accel_globals_ctor(zend_accel_globals *accel_globals) | |
GC_MAKE_PERSISTENT_LOCAL(accel_globals->key); | ||
} | ||
|
||
#ifdef ZTS | ||
static void accel_globals_dtor(zend_accel_globals *accel_globals) | ||
{ | ||
#ifdef ZTS | ||
zend_string_free(accel_globals->key); | ||
} | ||
#endif | ||
if (accel_globals->preloaded_internal_run_time_cache) { | ||
pefree(accel_globals->preloaded_internal_run_time_cache, 1); | ||
} | ||
} | ||
|
||
#ifdef HAVE_HUGE_CODE_PAGES | ||
# ifndef _WIN32 | ||
|
@@ -3402,6 +3406,8 @@ void accel_shutdown(void) | |
if (!ZCG(enabled) || !accel_startup_ok) { | ||
#ifdef ZTS | ||
ts_free_id(accel_globals_id); | ||
#else | ||
accel_globals_dtor(&accel_globals); | ||
#endif | ||
return; | ||
} | ||
|
@@ -3416,6 +3422,8 @@ void accel_shutdown(void) | |
|
||
#ifdef ZTS | ||
ts_free_id(accel_globals_id); | ||
#else | ||
accel_globals_dtor(&accel_globals); | ||
#endif | ||
|
||
if (!_file_cache_only) { | ||
|
@@ -4313,7 +4321,7 @@ static zend_persistent_script* preload_script_in_shared_memory(zend_persistent_s | |
return new_persistent_script; | ||
} | ||
|
||
static void preload_load(void) | ||
static void preload_load(size_t orig_map_ptr_static_last) | ||
{ | ||
/* Load into process tables */ | ||
zend_script *script = &ZCSG(preload_script)->script; | ||
|
@@ -4348,14 +4356,42 @@ static void preload_load(void) | |
if (EG(class_table)) { | ||
EG(persistent_classes_count) = EG(class_table)->nNumUsed; | ||
} | ||
if (CG(map_ptr_last) != ZCSG(map_ptr_last)) { | ||
size_t old_map_ptr_last = CG(map_ptr_last); | ||
|
||
size_t old_map_ptr_last = CG(map_ptr_last); | ||
if (zend_map_ptr_static_last != ZCSG(map_ptr_static_last) || old_map_ptr_last != ZCSG(map_ptr_last)) { | ||
CG(map_ptr_last) = ZCSG(map_ptr_last); | ||
CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096); | ||
CG(map_ptr_real_base) = perealloc(CG(map_ptr_real_base), CG(map_ptr_size) * sizeof(void*), 1); | ||
CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(ZCSG(map_ptr_last) + 1, 4096); | ||
zend_map_ptr_static_last = ZCSG(map_ptr_static_last); | ||
|
||
/* Grow map_ptr table as needed, but allocate once for static + regular map_ptrs */ | ||
size_t new_static_size = ZEND_MM_ALIGNED_SIZE_EX(zend_map_ptr_static_last, 4096); | ||
if (zend_map_ptr_static_size != new_static_size) { | ||
void *new_base = pemalloc((new_static_size + CG(map_ptr_size)) * sizeof(void *), 1); | ||
if (CG(map_ptr_real_base)) { | ||
memcpy((void **) new_base + new_static_size - zend_map_ptr_static_size, CG(map_ptr_real_base), (old_map_ptr_last + zend_map_ptr_static_size) * sizeof(void *)); | ||
pefree(CG(map_ptr_real_base), 1); | ||
} | ||
CG(map_ptr_real_base) = new_base; | ||
zend_map_ptr_static_size = new_static_size; | ||
} else { | ||
CG(map_ptr_real_base) = perealloc(CG(map_ptr_real_base), CG(map_ptr_size) * sizeof(void *), 1); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is this using |
||
} | ||
|
||
memset((void **) CG(map_ptr_real_base) + zend_map_ptr_static_size + old_map_ptr_last, 0, (CG(map_ptr_last) - old_map_ptr_last) * sizeof(void *)); | ||
CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(CG(map_ptr_real_base)); | ||
memset((void **) CG(map_ptr_real_base) + old_map_ptr_last, 0, | ||
(CG(map_ptr_last) - old_map_ptr_last) * sizeof(void *)); | ||
} | ||
|
||
if (orig_map_ptr_static_last != zend_map_ptr_static_last) { | ||
/* preloaded static entries currently are all runtime cache pointers, just assign them as such */ | ||
size_t runtime_cache_size = zend_internal_run_time_cache_reserved_size(); | ||
ZCG(preloaded_internal_run_time_cache_size) = (zend_map_ptr_static_last - orig_map_ptr_static_last) * runtime_cache_size; | ||
char *cache = pemalloc(ZCG(preloaded_internal_run_time_cache_size), 1); | ||
ZCG(preloaded_internal_run_time_cache) = cache; | ||
|
||
for (size_t cur_static_map_ptr = orig_map_ptr_static_last; cur_static_map_ptr < zend_map_ptr_static_last; ++cur_static_map_ptr) { | ||
*ZEND_MAP_PTR_STATIC_NUM_TO_PTR(cur_static_map_ptr) = cache; | ||
cache += runtime_cache_size; | ||
} | ||
} | ||
} | ||
|
||
|
@@ -4364,7 +4400,7 @@ static zend_result accel_preload(const char *config, bool in_child) | |
zend_file_handle file_handle; | ||
zend_result ret; | ||
char *orig_open_basedir; | ||
size_t orig_map_ptr_last; | ||
size_t orig_map_ptr_last, orig_map_ptr_static_last; | ||
uint32_t orig_compiler_options; | ||
|
||
ZCG(enabled) = false; | ||
|
@@ -4375,6 +4411,7 @@ static zend_result accel_preload(const char *config, bool in_child) | |
accelerator_orig_compile_file = preload_compile_file; | ||
|
||
orig_map_ptr_last = CG(map_ptr_last); | ||
orig_map_ptr_static_last = zend_map_ptr_static_last; | ||
|
||
/* Compile and execute preloading script */ | ||
zend_stream_init_filename(&file_handle, (char *) config); | ||
|
@@ -4554,7 +4591,7 @@ static zend_result accel_preload(const char *config, bool in_child) | |
SHM_PROTECT(); | ||
HANDLE_UNBLOCK_INTERRUPTIONS(); | ||
|
||
preload_load(); | ||
preload_load(orig_map_ptr_static_last); | ||
|
||
/* Store individual scripts with unlinked classes */ | ||
HANDLE_BLOCK_INTERRUPTIONS(); | ||
|
@@ -4806,7 +4843,7 @@ static zend_result accel_finish_startup(void) | |
|
||
if (ZCSG(preload_script)) { | ||
/* Preloading was done in another process */ | ||
preload_load(); | ||
preload_load(zend_map_ptr_static_last); | ||
zend_shared_alloc_unlock(); | ||
return SUCCESS; | ||
} | ||
|
@@ -4834,7 +4871,7 @@ static zend_result accel_finish_startup(void) | |
} | ||
|
||
if (ZCSG(preload_script)) { | ||
preload_load(); | ||
preload_load(zend_map_ptr_static_last); | ||
} | ||
|
||
zend_shared_alloc_unlock(); | ||
|
@@ -4848,6 +4885,12 @@ static zend_result accel_finish_startup(void) | |
#endif /* ZEND_WIN32 */ | ||
} | ||
|
||
static void accel_activate(void) { | ||
if (ZCG(preloaded_internal_run_time_cache)) { | ||
memset(ZCG(preloaded_internal_run_time_cache), 0, ZCG(preloaded_internal_run_time_cache_size)); | ||
} | ||
} | ||
|
||
ZEND_EXT_API zend_extension zend_extension_entry = { | ||
ACCELERATOR_PRODUCT_NAME, /* name */ | ||
PHP_VERSION, /* version */ | ||
|
@@ -4856,7 +4899,7 @@ ZEND_EXT_API zend_extension zend_extension_entry = { | |
"Copyright (c)", /* copyright */ | ||
accel_startup, /* startup */ | ||
NULL, /* shutdown */ | ||
NULL, /* per-script activation */ | ||
accel_activate, /* per-script activation */ | ||
#ifdef HAVE_JIT | ||
accel_deactivate, /* per-script deactivation */ | ||
#else | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -50,6 +50,7 @@ | |
|
||
#include "zend_extensions.h" | ||
#include "zend_compile.h" | ||
#include "zend_API.h" | ||
|
||
#include "Optimizer/zend_optimizer.h" | ||
#include "zend_accelerator_hash.h" | ||
|
@@ -216,6 +217,8 @@ typedef struct _zend_accel_globals { | |
#ifndef ZEND_WIN32 | ||
zend_ulong root_hash; | ||
#endif | ||
void *preloaded_internal_run_time_cache; | ||
size_t preloaded_internal_run_time_cache_size; | ||
/* preallocated shared-memory block to save current script */ | ||
void *mem; | ||
zend_persistent_script *current_persistent_script; | ||
|
@@ -278,6 +281,8 @@ typedef struct _zend_accel_shared_globals { | |
void *jit_traces; | ||
const void **jit_exit_groups; | ||
|
||
size_t map_ptr_static_last; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I hope no one is doing anything funky ABI-wise, they shouldn't of course... |
||
|
||
/* Interned Strings Support (must be the last element) */ | ||
ZEND_SET_ALIGNED(ZEND_STRING_TABLE_POS_ALIGNMENT, zend_string_table interned_strings); | ||
} zend_accel_shared_globals; | ||
|
@@ -310,7 +315,7 @@ extern const char *zps_api_failure_reason; | |
BEGIN_EXTERN_C() | ||
|
||
void accel_shutdown(void); | ||
zend_result accel_activate(INIT_FUNC_ARGS); | ||
ZEND_RINIT_FUNCTION(zend_accelerator); | ||
bwoebi marked this conversation as resolved.
Show resolved
Hide resolved
|
||
zend_result accel_post_deactivate(void); | ||
void zend_accel_schedule_restart(zend_accel_restart_reason reason); | ||
void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
--TEST-- | ||
Enum preloading with observers | ||
--EXTENSIONS-- | ||
opcache | ||
zend_test | ||
--INI-- | ||
opcache.enable=1 | ||
opcache.enable_cli=1 | ||
opcache.optimization_level=-1 | ||
opcache.preload={PWD}/preload_enum.inc | ||
zend_test.observer.enabled=1 | ||
zend_test.observer.show_output=1 | ||
zend_test.observer.observe_all=1 | ||
--SKIPIF-- | ||
<?php | ||
if (PHP_OS_FAMILY == 'Windows') die('skip Preloading is not supported on Windows'); | ||
?> | ||
--FILE-- | ||
<?php | ||
|
||
spl_autoload_register(static function ($class) { | ||
if ($class === 'MyEnum') { | ||
require_once(__DIR__ . '/preload_enum.inc'); | ||
} | ||
}); | ||
|
||
var_dump(MyEnum::cases()); | ||
|
||
?> | ||
--EXPECTF-- | ||
<!-- init '%spreload_enum.inc' --> | ||
<file '%spreload_enum.inc'> | ||
<!-- init var_dump() --> | ||
<var_dump> | ||
enum(MyEnum::Bar) | ||
</var_dump> | ||
</file '%spreload_enum.inc'> | ||
<!-- init '%spreload_enum_observed.php' --> | ||
<file '%spreload_enum_observed.php'> | ||
<!-- init spl_autoload_register() --> | ||
<spl_autoload_register> | ||
</spl_autoload_register> | ||
<!-- init MyEnum::cases() --> | ||
<MyEnum::cases> | ||
</MyEnum::cases> | ||
<!-- init var_dump() --> | ||
<var_dump> | ||
array(2) { | ||
[0]=> | ||
enum(MyEnum::Foo) | ||
[1]=> | ||
enum(MyEnum::Bar) | ||
} | ||
</var_dump> | ||
</file '%spreload_enum_observed.php'> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Noted. :)