The `zend_system_id` is a (true global) system ID that fingerprints a process state. When extensions add engine hooks during MINIT/startup, entropy is added the system ID for each hook. This allows extensions to identify that changes have been made to the engine since the last PHP process restart.
Closes GH-5871
- zend_stack_is_empty()
- zend_ts_hash_exists()
- zend_ts_hash_index_exists()
+ 9. Argument void to const char* in Zend Engine 4.0:
+ - zend_get_op_array_extension_handle()
+ 10. Argument zend_extension to const char* in Zend Engine 4.0:
+ - zend_get_resource_handle()
u. Instead of overwriting zend_error_cb extensions with debugging, monitoring
use-cases catching Errors/Exceptions are strongly encouraged to use
#include "zend_type_info.h"
#include "zend_smart_str.h"
#include "zend_observer.h"
+#include "zend_system_id.h"
/* Virtual current working directory support */
#include "zend_virtual_cwd.h"
*/
#include "zend_extensions.h"
+#include "zend_system_id.h"
ZEND_API zend_llist zend_extensions;
ZEND_API uint32_t zend_extension_flags = 0;
}
-ZEND_API int zend_get_resource_handle(zend_extension *extension)
+ZEND_API int zend_get_resource_handle(const char *module_name)
{
if (last_resource_number<ZEND_MAX_RESERVED_RESOURCES) {
- extension->resource_number = last_resource_number;
+ zend_add_system_entropy(module_name, "zend_get_resource_handle", &last_resource_number, sizeof(int));
return last_resource_number++;
} else {
return -1;
}
}
-ZEND_API int zend_get_op_array_extension_handle(void)
+ZEND_API int zend_get_op_array_extension_handle(const char *module_name)
{
+ zend_add_system_entropy(module_name, "zend_get_op_array_extension_handle", &zend_op_array_extension_handles, sizeof(int));
return zend_op_array_extension_handles++;
}
BEGIN_EXTERN_C()
extern ZEND_API int zend_op_array_extension_handles;
-ZEND_API int zend_get_resource_handle(zend_extension *extension);
-ZEND_API int zend_get_op_array_extension_handle(void);
+ZEND_API int zend_get_resource_handle(const char *module_name);
+ZEND_API int zend_get_op_array_extension_handle(const char *module_name);
ZEND_API void zend_extension_dispatch_message(int message, void *arg);
END_EXTERN_C()
/* We don't want to get an extension handle unless an ext installs an observer */
if (!ZEND_OBSERVER_ENABLED) {
zend_observer_fcall_op_array_extension =
- zend_get_op_array_extension_handle();
+ zend_get_op_array_extension_handle("Zend Observer");
/* ZEND_CALL_TRAMPOLINE has SPEC(OBSERVER) but zend_init_call_trampoline_op()
* is called before any extensions have registered as an observer. So we
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Sammy Kaye Powers <sammyk@php.net> |
+ | Dmitry Stogov <dmitry@php.net> |
+ +----------------------------------------------------------------------+
+ */
+
+#include "php.h"
+#include "zend_system_id.h"
+#include "zend_extensions.h"
+#include "ext/standard/md5.h"
+#include "ext/hash/php_hash.h"
+
+ZEND_API char zend_system_id[32];
+
+static PHP_MD5_CTX context;
+static int finalized = 0;
+
+ZEND_API ZEND_RESULT_CODE zend_add_system_entropy(const char *module_name, const char *hook_name, const void *data, size_t size)
+{
+ if (finalized == 0) {
+ PHP_MD5Update(&context, module_name, strlen(module_name));
+ PHP_MD5Update(&context, hook_name, strlen(hook_name));
+ if (size) {
+ PHP_MD5Update(&context, data, size);
+ }
+ return SUCCESS;
+ }
+ return FAILURE;
+}
+
+#define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
+
+void zend_startup_system_id(void)
+{
+ PHP_MD5Init(&context);
+ PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
+ PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
+ PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
+ if (strstr(PHP_VERSION, "-dev") != 0) {
+ /* Development versions may be changed from build to build */
+ PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
+ PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
+ }
+ zend_system_id[0] = '\0';
+}
+
+#define ZEND_HOOK_AST_PROCESS (1 << 0)
+#define ZEND_HOOK_COMPILE_FILE (1 << 1)
+#define ZEND_HOOK_EXECUTE_EX (1 << 2)
+#define ZEND_HOOK_EXECUTE_INTERNAL (1 << 3)
+
+void zend_finalize_system_id(void)
+{
+ unsigned char digest[16];
+ zend_uchar hooks = 0;
+
+ if (zend_ast_process) {
+ hooks |= ZEND_HOOK_AST_PROCESS;
+ }
+ if (zend_compile_file != compile_file) {
+ hooks |= ZEND_HOOK_COMPILE_FILE;
+ }
+ if (zend_execute_ex != execute_ex) {
+ hooks |= ZEND_HOOK_EXECUTE_EX;
+ }
+ if (zend_execute_internal) {
+ hooks |= ZEND_HOOK_EXECUTE_INTERNAL;
+ }
+ PHP_MD5Update(&context, &hooks, sizeof hooks);
+
+ for (int16_t i = 0; i < 256; i++) {
+ if (zend_get_user_opcode_handler((zend_uchar) i) != NULL) {
+ PHP_MD5Update(&context, &i, sizeof i);
+ }
+ }
+
+ PHP_MD5Final(digest, &context);
+ php_hash_bin2hex(zend_system_id, digest, sizeof digest);
+ finalized = 1;
+}
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Sammy Kaye Powers <sammyk@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifndef ZEND_SYSTEM_ID_H
+#define ZEND_SYSTEM_ID_H
+
+BEGIN_EXTERN_C()
+/* True global; Write-only during MINIT/startup */
+extern ZEND_API char zend_system_id[32];
+
+ZEND_API ZEND_RESULT_CODE zend_add_system_entropy(const char *module_name, const char *hook_name, const void *data, size_t size);
+END_EXTERN_C()
+
+void zend_startup_system_id(void);
+void zend_finalize_system_id(void);
+
+#endif /* ZEND_SYSTEM_ID_H */
zend_closures.c zend_weakrefs.c zend_float.c zend_string.c zend_signal.c zend_generators.c \
zend_virtual_cwd.c zend_ast.c zend_objects.c zend_object_handlers.c zend_objects_API.c \
zend_default_classes.c zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_gdb.c \
- zend_observer.c, \
+ zend_observer.c zend_system_id.c, \
-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1)
PHP_ADD_BUILD_DIR(main main/streams)
int zend_func_info_startup(void)
{
- zend_extension dummy;
size_t i;
if (zend_func_info_rid == -1) {
- zend_func_info_rid = zend_get_resource_handle(&dummy);
+ zend_func_info_rid = zend_get_resource_handle("Zend Optimizer");
if (zend_func_info_rid < 0) {
return FAILURE;
}
zend_accel_shared_globals *accel_shared_globals = NULL;
/* true globals, no need for thread safety */
-char accel_system_id[32];
#ifdef ZEND_WIN32
char accel_uname_id[32];
#endif
static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
static zend_result (*orig_post_startup_cb)(void);
-static void accel_gen_system_id(void);
static zend_result accel_post_startup(void);
static int accel_finish_startup(void);
memset(accel_globals, 0, sizeof(zend_accel_globals));
}
-#define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
-
-static void accel_gen_system_id(void)
-{
- PHP_MD5_CTX context;
- unsigned char digest[16];
- zend_module_entry *module;
- zend_extension *extension;
- zend_llist_position pos;
-
- PHP_MD5Init(&context);
- PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
- PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
- PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
- if (strstr(PHP_VERSION, "-dev") != 0) {
- /* Development versions may be changed from build to build */
- PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
- PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
- }
- /* Modules may have changed after restart which can cause dangling pointers from
- * custom opcode handlers in the second-level cache files
- */
- ZEND_HASH_FOREACH_PTR(&module_registry, module) {
- PHP_MD5Update(&context, module->name, strlen(module->name));
- if (module->version != NULL) {
- PHP_MD5Update(&context, module->version, strlen(module->version));
- }
- } ZEND_HASH_FOREACH_END();
- extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
- while (extension) {
- PHP_MD5Update(&context, extension->name, strlen(extension->name));
- if (extension->version != NULL) {
- PHP_MD5Update(&context, extension->version, strlen(extension->version));
- }
- extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
- }
- PHP_MD5Final(digest, &context);
- php_hash_bin2hex(accel_system_id, digest, sizeof digest);
-}
-
#ifdef HAVE_HUGE_CODE_PAGES
# ifndef _WIN32
# include <sys/mman.h>
# endif
#endif
- accel_gen_system_id();
-
if (start_accel_module() == FAILURE) {
accel_startup_ok = 0;
zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
zend_string_table interned_strings;
} zend_accel_shared_globals;
-extern char accel_system_id[32];
#ifdef ZEND_WIN32
extern char accel_uname_id[32];
#endif
return FAILURE;
}
- zend_jit_profile_counter_rid = zend_get_op_array_extension_handle();
+ zend_jit_profile_counter_rid = zend_get_op_array_extension_handle(ACCELERATOR_PRODUCT_NAME);
#ifdef HAVE_GDB
zend_jit_gdb_init();
#include "zend_shared_alloc.h"
#include "zend_accelerator_util_funcs.h"
#include "zend_execute.h"
+#include "zend_system_id.h"
#include "SAPI.h"
#include "tsrm_win32.h"
#include "win32/winutil.h"
static char *create_name_with_username(char *name)
{
static char newname[MAXPATHLEN + 32 + 4 + 1 + 32 + 21];
- snprintf(newname, sizeof(newname) - 1, "%s@%.32s@%.20s@%.32s", name, accel_uname_id, sapi_module.name, accel_system_id);
+ snprintf(newname, sizeof(newname) - 1, "%s@%.32s@%.20s@%.32s", name, accel_uname_id, sapi_module.name, zend_system_id);
return newname;
}
#include "zend_vm.h"
#include "zend_interfaces.h"
#include "zend_attributes.h"
+#include "zend_system_id.h"
#include "php.h"
#ifdef ZEND_WIN32
zend_persistent_script *new_script;
memcpy(info->magic, "OPCACHE", 8);
- memcpy(info->system_id, accel_system_id, 32);
+ memcpy(info->system_id, zend_system_id, 32);
info->mem_size = script->size;
info->str_size = 0;
info->script_offset = (char*)script - (char*)script->mem;
filename = emalloc(len + 33 + ZSTR_LEN(script_path) + sizeof(SUFFIX));
memcpy(filename, ZCG(accel_directives).file_cache, len);
filename[len] = '/';
- memcpy(filename + len + 1, accel_system_id, 32);
+ memcpy(filename + len + 1, zend_system_id, 32);
memcpy(filename + len + 33, ZSTR_VAL(script_path), ZSTR_LEN(script_path));
memcpy(filename + len + 33 + ZSTR_LEN(script_path), SUFFIX, sizeof(SUFFIX));
#else
len += 1 + 32;
filename[len] = '\\';
- memcpy(filename + len + 1, accel_system_id, 32);
+ memcpy(filename + len + 1, zend_system_id, 32);
if (ZSTR_LEN(script_path) >= 7 && ':' == ZSTR_VAL(script_path)[4] && '/' == ZSTR_VAL(script_path)[5] && '/' == ZSTR_VAL(script_path)[6]) {
/* phar:// or file:// */
efree(filename);
return NULL;
}
- if (memcmp(info.system_id, accel_system_id, 32) != 0) {
+ if (memcmp(info.system_id, zend_system_id, 32) != 0) {
zend_accel_error(ACCEL_LOG_WARNING, "opcache cannot read from file '%s' (wrong \"system_id\")\n", filename);
zend_file_cache_flock(fd, LOCK_UN);
close(fd);
#include "zend_ini.h"
#include "zend_dtrace.h"
#include "zend_observer.h"
+#include "zend_system_id.h"
#include "php_content_types.h"
#include "php_ticks.h"
zend_set_utility_values(&zuv);
php_startup_sapi_content_types();
+ /* Begin to fingerprint the process state */
+ zend_startup_system_id();
+
/* startup extensions statically compiled in */
if (php_register_internal_extensions_func() == FAILURE) {
php_printf("Unable to start builtin modules\n");
module->info_func = PHP_MINFO(php_core);
}
+ /* Extensions that add engine hooks after this point do so at their own peril */
+ zend_finalize_system_id();
+
module_initialized = 1;
if (zend_post_startup() != SUCCESS) {
zend_object_handlers.c zend_objects_API.c \
zend_default_classes.c zend_execute.c zend_strtod.c zend_gc.c zend_closures.c zend_weakrefs.c \
zend_float.c zend_string.c zend_generators.c zend_virtual_cwd.c zend_ast.c \
- zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_observer.c");
+ zend_inheritance.c zend_smart_str.c zend_cpuinfo.c zend_observer.c zend_system_id.c");
ADD_FLAG("CFLAGS_BD_ZEND", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1");
if (VS_TOOLSET && VCVERS >= 1914) {