Fix delayed early binding with optimization

It's possible for delayed early binding opcodes to get optimized
away if they are "unreachable". However, we still need to attempt
early binding for them. (In some cases we also corrupt the early
binding list outright during optimization, which is how I got here.)

Fix this by storing information about delayed early binding
independently of DECLARE_CLASS_DELAYED opcodes, so early binding is
performed even after the opcode has been dropped.
This commit is contained in:
Nikita Popov 2021-09-27 12:21:40 +02:00 committed by Nikita Popov
parent fb296cf0ba
commit c19977d054
17 changed files with 212 additions and 115 deletions

View file

@ -1119,13 +1119,6 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array, zend_op
free_alloca(map, use_heap); free_alloca(map, use_heap);
} }
/* adjust early binding list */
if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
ZEND_ASSERT(op_array == &ctx->script->main_op_array);
ctx->script->first_early_binding_opline =
zend_build_delayed_early_binding_list(op_array);
}
/* rebuild map (just for printing) */ /* rebuild map (just for printing) */
memset(cfg->map, -1, sizeof(int) * op_array->last); memset(cfg->map, -1, sizeof(int) * op_array->last);
for (int n = 0; n < cfg->blocks_count; n++) { for (int n = 0; n < cfg->blocks_count; n++) {

View file

@ -235,17 +235,6 @@ static void zend_ssa_remove_nops(zend_op_array *op_array, zend_ssa *ssa, zend_op
} }
} }
/* update early binding list */
if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
uint32_t *opline_num = &ctx->script->first_early_binding_opline;
ZEND_ASSERT(op_array == &ctx->script->main_op_array);
do {
*opline_num -= shiftlist[*opline_num];
opline_num = &op_array->opcodes[*opline_num].result.opline_num;
} while (*opline_num != (uint32_t)-1);
}
/* update call graph */ /* update call graph */
if (func_info) { if (func_info) {
zend_call_info *call_info = func_info->callee_info; zend_call_info *call_info = func_info->callee_info;

View file

@ -89,17 +89,6 @@ void zend_optimizer_nop_removal(zend_op_array *op_array, zend_optimizer_ctx *ctx
op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end]; op_array->try_catch_array[j].finally_end -= shiftlist[op_array->try_catch_array[j].finally_end];
} }
} }
/* update early binding list */
if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
uint32_t *opline_num = &ctx->script->first_early_binding_opline;
ZEND_ASSERT(op_array == &ctx->script->main_op_array);
do {
*opline_num -= shiftlist[*opline_num];
opline_num = &op_array->opcodes[*opline_num].result.opline_num;
} while (*opline_num != (uint32_t)-1);
}
} }
free_alloca(shiftlist, use_heap); free_alloca(shiftlist, use_heap);
} }

View file

@ -86,7 +86,6 @@ typedef struct _zend_script {
zend_op_array main_op_array; zend_op_array main_op_array;
HashTable function_table; HashTable function_table;
HashTable class_table; HashTable class_table;
uint32_t first_early_binding_opline; /* the linked list of delayed declarations */
} zend_script; } zend_script;
typedef void (*zend_optimizer_pass_t)(zend_script *, void *context); typedef void (*zend_optimizer_pass_t)(zend_script *, void *context);

View file

@ -0,0 +1,6 @@
<?php
var_dump(new B);
if (true) {
return;
}
class B extends A {}

View file

@ -0,0 +1,10 @@
--TEST--
Early bound class in otherwise unreachable code
--FILE--
<?php
class A {}
require __DIR__ . '/early_binding_unreachable.inc';
?>
--EXPECT--
object(B)#1 (0) {
}

View file

@ -1322,73 +1322,6 @@ static void zend_mark_function_as_generator(void) /* {{{ */
} }
/* }}} */ /* }}} */
ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array) /* {{{ */
{
if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
uint32_t first_early_binding_opline = (uint32_t)-1;
uint32_t *prev_opline_num = &first_early_binding_opline;
zend_op *opline = op_array->opcodes;
zend_op *end = opline + op_array->last;
while (opline < end) {
if (opline->opcode == ZEND_DECLARE_CLASS_DELAYED) {
*prev_opline_num = opline - op_array->opcodes;
prev_opline_num = &opline->result.opline_num;
}
++opline;
}
*prev_opline_num = -1;
return first_early_binding_opline;
}
return (uint32_t)-1;
}
/* }}} */
ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline) /* {{{ */
{
if (first_early_binding_opline != (uint32_t)-1) {
bool orig_in_compilation = CG(in_compilation);
uint32_t opline_num = first_early_binding_opline;
void **run_time_cache;
if (!ZEND_MAP_PTR(op_array->run_time_cache)) {
void *ptr;
ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE);
ptr = emalloc(op_array->cache_size + sizeof(void*));
ZEND_MAP_PTR_INIT(op_array->run_time_cache, ptr);
ptr = (char*)ptr + sizeof(void*);
ZEND_MAP_PTR_SET(op_array->run_time_cache, ptr);
memset(ptr, 0, op_array->cache_size);
}
run_time_cache = RUN_TIME_CACHE(op_array);
CG(in_compilation) = 1;
while (opline_num != (uint32_t)-1) {
const zend_op *opline = &op_array->opcodes[opline_num];
zval *lcname = RT_CONSTANT(opline, opline->op1);
zval *zv = zend_hash_find_known_hash(EG(class_table), Z_STR_P(lcname + 1));
if (zv) {
zend_class_entry *ce = Z_CE_P(zv);
zend_string *lc_parent_name = Z_STR_P(RT_CONSTANT(opline, opline->op2));
zend_class_entry *parent_ce = zend_hash_find_ex_ptr(EG(class_table), lc_parent_name, 1);
if (parent_ce) {
ce = zend_try_early_bind(ce, parent_ce, Z_STR_P(lcname), zv);
if (ce) {
/* Store in run-time cache */
((void**)((char*)run_time_cache + opline->extended_value))[0] = ce;
}
}
}
opline_num = op_array->opcodes[opline_num].result.opline_num;
}
CG(in_compilation) = orig_in_compilation;
}
}
/* }}} */
ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, bool internal) /* {{{ */ ZEND_API zend_string *zend_mangle_property_name(const char *src1, size_t src1_length, const char *src2, size_t src2_length, bool internal) /* {{{ */
{ {
size_t prop_name_length = 1 + src1_length + 1 + src2_length; size_t prop_name_length = 1 + src1_length + 1 + src2_length;

View file

@ -791,8 +791,6 @@ ZEND_API zend_class_entry *zend_bind_class_in_slot(
zval *class_table_slot, zval *lcname, zend_string *lc_parent_name); zval *class_table_slot, zval *lcname, zend_string *lc_parent_name);
ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname); ZEND_API zend_result do_bind_function(zend_function *func, zval *lcname);
ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name); ZEND_API zend_result do_bind_class(zval *lcname, zend_string *lc_parent_name);
ZEND_API uint32_t zend_build_delayed_early_binding_list(const zend_op_array *op_array);
ZEND_API void zend_do_delayed_early_binding(zend_op_array *op_array, uint32_t first_early_binding_opline);
void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline); void zend_resolve_goto_label(zend_op_array *op_array, zend_op *opline);

View file

@ -3029,7 +3029,7 @@ static zend_always_inline bool register_early_bound_ce(zval *delayed_early_bindi
return zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL; return zend_hash_add_ptr(CG(class_table), lcname, ce) != NULL;
} }
zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding) /* {{{ */ ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding) /* {{{ */
{ {
inheritance_status status; inheritance_status status;
zend_class_entry *proto = NULL; zend_class_entry *proto = NULL;

View file

@ -34,7 +34,7 @@ ZEND_API zend_class_entry *zend_do_link_class(zend_class_entry *ce, zend_string
void zend_verify_abstract_class(zend_class_entry *ce); void zend_verify_abstract_class(zend_class_entry *ce);
void zend_build_properties_info_table(zend_class_entry *ce); void zend_build_properties_info_table(zend_class_entry *ce);
zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding); ZEND_API zend_class_entry *zend_try_early_bind(zend_class_entry *ce, zend_class_entry *parent_ce, zend_string *lcname, zval *delayed_early_binding);
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces); ZEND_API extern zend_class_entry* (*zend_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies); ZEND_API extern zend_class_entry* (*zend_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);

View file

@ -1471,6 +1471,7 @@ static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script
orig_compiler_options = CG(compiler_options); orig_compiler_options = CG(compiler_options);
CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE; CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level); zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
zend_accel_finalize_delayed_early_binding_list(new_persistent_script);
CG(compiler_options) = orig_compiler_options; CG(compiler_options) = orig_compiler_options;
*from_shared_memory = 1; *from_shared_memory = 1;
@ -1488,6 +1489,7 @@ static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_scr
CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE; CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
} }
zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level); zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
zend_accel_finalize_delayed_early_binding_list(new_persistent_script);
CG(compiler_options) = orig_compiler_options; CG(compiler_options) = orig_compiler_options;
/* exclusive lock */ /* exclusive lock */
@ -1810,10 +1812,7 @@ static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handl
new_persistent_script->script.main_op_array = *op_array; new_persistent_script->script.main_op_array = *op_array;
zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script); zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script); zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
new_persistent_script->script.first_early_binding_opline = zend_accel_build_delayed_early_binding_list(new_persistent_script);
(op_array->fn_flags & ZEND_ACC_EARLY_BINDING) ?
zend_build_delayed_early_binding_list(op_array) :
(uint32_t)-1;
new_persistent_script->num_warnings = EG(num_errors); new_persistent_script->num_warnings = EG(num_errors);
new_persistent_script->warnings = EG(errors); new_persistent_script->warnings = EG(errors);
EG(num_errors) = 0; EG(num_errors) = 0;
@ -3604,7 +3603,6 @@ static zend_op_array *preload_compile_file(zend_file_handle *file_handle, int ty
zend_persistent_script *script; zend_persistent_script *script;
script = create_persistent_script(); script = create_persistent_script();
script->script.first_early_binding_opline = (uint32_t)-1;
script->script.filename = zend_string_copy(op_array->filename); script->script.filename = zend_string_copy(op_array->filename);
zend_string_hash_val(script->script.filename); zend_string_hash_val(script->script.filename);
script->script.main_op_array = *op_array; script->script.main_op_array = *op_array;
@ -4023,8 +4021,9 @@ static void preload_link(void)
preload_remove_declares(op_array); preload_remove_declares(op_array);
if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) { if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
script->script.first_early_binding_opline = zend_build_delayed_early_binding_list(op_array); zend_accel_free_delayed_early_binding_list(script);
if (script->script.first_early_binding_opline == (uint32_t)-1) { zend_accel_build_delayed_early_binding_list(script);
if (!script->num_early_bindings) {
op_array->fn_flags &= ~ZEND_ACC_EARLY_BINDING; op_array->fn_flags &= ~ZEND_ACC_EARLY_BINDING;
} }
} }
@ -4195,6 +4194,7 @@ static void preload_optimize(zend_persistent_script *script)
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level); zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
zend_accel_finalize_delayed_early_binding_list(script);
ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) { ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
preload_fix_trait_methods(ce); preload_fix_trait_methods(ce);
@ -4210,6 +4210,7 @@ static void preload_optimize(zend_persistent_script *script)
ZEND_HASH_FOREACH_PTR(preload_scripts, script) { ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level); zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level);
zend_accel_finalize_delayed_early_binding_list(script);
} ZEND_HASH_FOREACH_END(); } ZEND_HASH_FOREACH_END();
} }
@ -4522,8 +4523,6 @@ static int accel_preload(const char *config, bool in_child)
script->script.filename = CG(compiled_filename); script->script.filename = CG(compiled_filename);
CG(compiled_filename) = NULL; CG(compiled_filename) = NULL;
script->script.first_early_binding_opline = (uint32_t)-1;
preload_move_user_functions(CG(function_table), &script->script.function_table); preload_move_user_functions(CG(function_table), &script->script.function_table);
preload_move_user_classes(CG(class_table), &script->script.class_table); preload_move_user_classes(CG(class_table), &script->script.class_table);

View file

@ -109,6 +109,13 @@ typedef enum _zend_accel_restart_reason {
ACCEL_RESTART_USER /* restart scheduled by opcache_reset() */ ACCEL_RESTART_USER /* restart scheduled by opcache_reset() */
} zend_accel_restart_reason; } zend_accel_restart_reason;
typedef struct _zend_early_binding {
zend_string *lcname;
zend_string *rtd_key;
zend_string *lc_parent_name;
uint32_t cache_slot;
} zend_early_binding;
typedef struct _zend_persistent_script { typedef struct _zend_persistent_script {
zend_script script; zend_script script;
zend_long compiler_halt_offset; /* position of __HALT_COMPILER or -1 */ zend_long compiler_halt_offset; /* position of __HALT_COMPILER or -1 */
@ -118,7 +125,9 @@ typedef struct _zend_persistent_script {
bool is_phar; bool is_phar;
bool empty; bool empty;
uint32_t num_warnings; uint32_t num_warnings;
uint32_t num_early_bindings;
zend_error_info **warnings; zend_error_info **warnings;
zend_early_binding *early_bindings;
void *mem; /* shared memory area used by script structures */ void *mem; /* shared memory area used by script structures */
size_t size; /* size of used shared memory */ size_t size; /* size of used shared memory */

View file

@ -21,6 +21,7 @@
#include "zend_API.h" #include "zend_API.h"
#include "zend_constants.h" #include "zend_constants.h"
#include "zend_inheritance.h"
#include "zend_accelerator_util_funcs.h" #include "zend_accelerator_util_funcs.h"
#include "zend_persist.h" #include "zend_persist.h"
#include "zend_shared_alloc.h" #include "zend_shared_alloc.h"
@ -71,6 +72,8 @@ void free_persistent_script(zend_persistent_script *persistent_script, int destr
efree(persistent_script->warnings); efree(persistent_script->warnings);
} }
zend_accel_free_delayed_early_binding_list(persistent_script);
efree(persistent_script); efree(persistent_script);
} }
@ -225,6 +228,116 @@ static void zend_accel_class_hash_copy(HashTable *target, HashTable *source)
return; return;
} }
void zend_accel_build_delayed_early_binding_list(zend_persistent_script *persistent_script)
{
zend_op_array *op_array = &persistent_script->script.main_op_array;
if (!(op_array->fn_flags & ZEND_ACC_EARLY_BINDING)) {
return;
}
zend_op *end = op_array->opcodes + op_array->last;
for (zend_op *opline = op_array->opcodes; opline < end; opline++) {
if (opline->opcode == ZEND_DECLARE_CLASS_DELAYED) {
persistent_script->num_early_bindings++;
}
}
zend_early_binding *early_binding = persistent_script->early_bindings =
emalloc(sizeof(zend_early_binding) * persistent_script->num_early_bindings);
for (zend_op *opline = op_array->opcodes; opline < end; opline++) {
if (opline->opcode == ZEND_DECLARE_CLASS_DELAYED) {
zval *lcname = RT_CONSTANT(opline, opline->op1);
early_binding->lcname = zend_string_copy(Z_STR_P(lcname));
early_binding->rtd_key = zend_string_copy(Z_STR_P(lcname + 1));
early_binding->lc_parent_name =
zend_string_copy(Z_STR_P(RT_CONSTANT(opline, opline->op2)));
early_binding->cache_slot = (uint32_t) -1;
early_binding++;
}
}
}
void zend_accel_finalize_delayed_early_binding_list(zend_persistent_script *persistent_script)
{
if (!persistent_script->num_early_bindings) {
return;
}
zend_early_binding *early_binding = persistent_script->early_bindings;
zend_early_binding *early_binding_end = early_binding + persistent_script->num_early_bindings;
zend_op_array *op_array = &persistent_script->script.main_op_array;
zend_op *opline_end = op_array->opcodes + op_array->last;
for (zend_op *opline = op_array->opcodes; opline < opline_end; opline++) {
if (opline->opcode == ZEND_DECLARE_CLASS_DELAYED) {
zend_string *rtd_key = Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1);
/* Skip early_binding entries that don't match, maybe their DECLARE_CLASS_DELAYED
* was optimized away. */
while (!zend_string_equals(early_binding->rtd_key, rtd_key)) {
early_binding++;
if (early_binding >= early_binding_end) {
return;
}
}
early_binding->cache_slot = opline->extended_value;
early_binding++;
if (early_binding >= early_binding_end) {
return;
}
}
}
}
void zend_accel_free_delayed_early_binding_list(zend_persistent_script *persistent_script)
{
if (persistent_script->num_early_bindings) {
for (uint32_t i = 0; i < persistent_script->num_early_bindings; i++) {
zend_early_binding *early_binding = &persistent_script->early_bindings[i];
zend_string_release(early_binding->lcname);
zend_string_release(early_binding->rtd_key);
zend_string_release(early_binding->lc_parent_name);
}
efree(persistent_script->early_bindings);
persistent_script->early_bindings = NULL;
persistent_script->num_early_bindings = 0;
}
}
static void zend_accel_do_delayed_early_binding(
zend_persistent_script *persistent_script, zend_op_array *op_array)
{
ZEND_ASSERT(!ZEND_MAP_PTR(op_array->run_time_cache));
ZEND_ASSERT(op_array->fn_flags & ZEND_ACC_HEAP_RT_CACHE);
void *ptr = emalloc(op_array->cache_size + sizeof(void*));
ZEND_MAP_PTR_INIT(op_array->run_time_cache, ptr);
char *run_time_cache = (char *) ptr + sizeof(void*);
ZEND_MAP_PTR_SET(op_array->run_time_cache, run_time_cache);
memset(run_time_cache, 0, op_array->cache_size);
zend_string *orig_compiled_filename = CG(compiled_filename);
bool orig_in_compilation = CG(in_compilation);
CG(compiled_filename) = persistent_script->script.filename;
CG(in_compilation) = 1;
for (uint32_t i = 0; i < persistent_script->num_early_bindings; i++) {
zend_early_binding *early_binding = &persistent_script->early_bindings[i];
zval *zv = zend_hash_find_known_hash(EG(class_table), early_binding->rtd_key);
if (zv) {
zend_class_entry *ce = Z_CE_P(zv);
zend_class_entry *parent_ce =
zend_hash_find_ex_ptr(EG(class_table), early_binding->lc_parent_name, 1);
if (parent_ce) {
ce = zend_try_early_bind(ce, parent_ce, early_binding->lcname, zv);
if (ce && early_binding->cache_slot != (uint32_t) -1) {
*(void**)(run_time_cache + early_binding->cache_slot) = ce;
}
}
}
}
CG(compiled_filename) = orig_compiled_filename;
CG(in_compilation) = orig_in_compilation;
}
zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory) zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory)
{ {
zend_op_array *op_array; zend_op_array *op_array;
@ -259,11 +372,8 @@ zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script,
} }
} }
if (persistent_script->script.first_early_binding_opline != (uint32_t)-1) { if (persistent_script->num_early_bindings) {
zend_string *orig_compiled_filename = CG(compiled_filename); zend_accel_do_delayed_early_binding(persistent_script, op_array);
CG(compiled_filename) = persistent_script->script.filename;
zend_do_delayed_early_binding(op_array, persistent_script->script.first_early_binding_opline);
CG(compiled_filename) = orig_compiled_filename;
} }
if (UNEXPECTED(!from_shared_memory)) { if (UNEXPECTED(!from_shared_memory)) {

View file

@ -30,6 +30,9 @@ void free_persistent_script(zend_persistent_script *persistent_script, int destr
void zend_accel_move_user_functions(HashTable *str, uint32_t count, zend_script *script); void zend_accel_move_user_functions(HashTable *str, uint32_t count, zend_script *script);
void zend_accel_move_user_classes(HashTable *str, uint32_t count, zend_script *script); void zend_accel_move_user_classes(HashTable *str, uint32_t count, zend_script *script);
void zend_accel_build_delayed_early_binding_list(zend_persistent_script *persistent_script);
void zend_accel_finalize_delayed_early_binding_list(zend_persistent_script *persistent_script);
void zend_accel_free_delayed_early_binding_list(zend_persistent_script *persistent_script);
zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory); zend_op_array* zend_accel_load_script(zend_persistent_script *persistent_script, int from_shared_memory);

View file

@ -889,6 +889,21 @@ static void zend_file_cache_serialize_warnings(
} }
} }
static void zend_file_cache_serialize_early_bindings(
zend_persistent_script *script, zend_file_cache_metainfo *info, void *buf)
{
if (script->early_bindings) {
SERIALIZE_PTR(script->early_bindings);
zend_early_binding *early_bindings = script->early_bindings;
UNSERIALIZE_PTR(early_bindings);
for (uint32_t i = 0; i < script->num_early_bindings; i++) {
SERIALIZE_STR(early_bindings[i].lcname);
SERIALIZE_STR(early_bindings[i].rtd_key);
SERIALIZE_STR(early_bindings[i].lc_parent_name);
}
}
}
static void zend_file_cache_serialize(zend_persistent_script *script, static void zend_file_cache_serialize(zend_persistent_script *script,
zend_file_cache_metainfo *info, zend_file_cache_metainfo *info,
void *buf) void *buf)
@ -911,6 +926,7 @@ static void zend_file_cache_serialize(zend_persistent_script *script,
zend_file_cache_serialize_hash(&new_script->script.function_table, script, info, buf, zend_file_cache_serialize_func); zend_file_cache_serialize_hash(&new_script->script.function_table, script, info, buf, zend_file_cache_serialize_func);
zend_file_cache_serialize_op_array(&new_script->script.main_op_array, script, info, buf); zend_file_cache_serialize_op_array(&new_script->script.main_op_array, script, info, buf);
zend_file_cache_serialize_warnings(new_script, info, buf); zend_file_cache_serialize_warnings(new_script, info, buf);
zend_file_cache_serialize_early_bindings(new_script, info, buf);
new_script->mem = NULL; new_script->mem = NULL;
} }
@ -1667,6 +1683,18 @@ static void zend_file_cache_unserialize_warnings(zend_persistent_script *script,
} }
} }
static void zend_file_cache_unserialize_early_bindings(zend_persistent_script *script, void *buf)
{
if (script->early_bindings) {
UNSERIALIZE_PTR(script->early_bindings);
for (uint32_t i = 0; i < script->num_early_bindings; i++) {
UNSERIALIZE_STR(script->early_bindings[i].lcname);
UNSERIALIZE_STR(script->early_bindings[i].rtd_key);
UNSERIALIZE_STR(script->early_bindings[i].lc_parent_name);
}
}
}
static void zend_file_cache_unserialize(zend_persistent_script *script, static void zend_file_cache_unserialize(zend_persistent_script *script,
void *buf) void *buf)
{ {
@ -1680,6 +1708,7 @@ static void zend_file_cache_unserialize(zend_persistent_script *script,
script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR); script, buf, zend_file_cache_unserialize_func, ZEND_FUNCTION_DTOR);
zend_file_cache_unserialize_op_array(&script->script.main_op_array, script, buf); zend_file_cache_unserialize_op_array(&script->script.main_op_array, script, buf);
zend_file_cache_unserialize_warnings(script, buf); zend_file_cache_unserialize_warnings(script, buf);
zend_file_cache_unserialize_early_bindings(script, buf);
} }
zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle) zend_persistent_script *zend_file_cache_script_load(zend_file_handle *file_handle)

View file

@ -1278,6 +1278,20 @@ zend_error_info **zend_persist_warnings(uint32_t num_warnings, zend_error_info *
return warnings; return warnings;
} }
static zend_early_binding *zend_persist_early_bindings(
uint32_t num_early_bindings, zend_early_binding *early_bindings) {
if (early_bindings) {
early_bindings = zend_shared_memdup_free(
early_bindings, num_early_bindings * sizeof(zend_early_binding));
for (uint32_t i = 0; i < num_early_bindings; i++) {
zend_accel_store_interned_string(early_bindings[i].lcname);
zend_accel_store_interned_string(early_bindings[i].rtd_key);
zend_accel_store_interned_string(early_bindings[i].lc_parent_name);
}
}
return early_bindings;
}
zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, int for_shm) zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script, int for_shm)
{ {
Bucket *p; Bucket *p;
@ -1332,6 +1346,8 @@ zend_persistent_script *zend_accel_script_persist(zend_persistent_script *script
#endif #endif
} }
script->warnings = zend_persist_warnings(script->num_warnings, script->warnings); script->warnings = zend_persist_warnings(script->num_warnings, script->warnings);
script->early_bindings = zend_persist_early_bindings(
script->num_early_bindings, script->early_bindings);
if (for_shm) { if (for_shm) {
ZCSG(map_ptr_last) = CG(map_ptr_last); ZCSG(map_ptr_last) = CG(map_ptr_last);

View file

@ -568,6 +568,18 @@ void zend_persist_warnings_calc(uint32_t num_warnings, zend_error_info **warning
} }
} }
static void zend_persist_early_bindings_calc(
uint32_t num_early_bindings, zend_early_binding *early_bindings)
{
ADD_SIZE(sizeof(zend_early_binding) * num_early_bindings);
for (uint32_t i = 0; i < num_early_bindings; i++) {
zend_early_binding *early_binding = &early_bindings[i];
ADD_INTERNED_STRING(early_binding->lcname);
ADD_INTERNED_STRING(early_binding->rtd_key);
ADD_INTERNED_STRING(early_binding->lc_parent_name);
}
}
uint32_t zend_accel_script_persist_calc(zend_persistent_script *new_persistent_script, int for_shm) uint32_t zend_accel_script_persist_calc(zend_persistent_script *new_persistent_script, int for_shm)
{ {
Bucket *p; Bucket *p;
@ -606,6 +618,8 @@ uint32_t zend_accel_script_persist_calc(zend_persistent_script *new_persistent_s
zend_persist_op_array_calc_ex(&new_persistent_script->script.main_op_array); zend_persist_op_array_calc_ex(&new_persistent_script->script.main_op_array);
zend_persist_warnings_calc( zend_persist_warnings_calc(
new_persistent_script->num_warnings, new_persistent_script->warnings); new_persistent_script->num_warnings, new_persistent_script->warnings);
zend_persist_early_bindings_calc(
new_persistent_script->num_early_bindings, new_persistent_script->early_bindings);
new_persistent_script->corrupted = 0; new_persistent_script->corrupted = 0;