mirror of
https://github.com/php/php-src.git
synced 2025-08-16 14:08:47 +02:00
Allow loading FFI bindings through ffi.preload directive
This commit is contained in:
parent
1c9bfcb6a7
commit
1417352dda
5 changed files with 124 additions and 27 deletions
|
@ -1094,6 +1094,9 @@ END_EXTERN_C()
|
||||||
/* disable jumptable optimization for switch statements */
|
/* disable jumptable optimization for switch statements */
|
||||||
#define ZEND_COMPILE_NO_JUMPTABLES (1<<16)
|
#define ZEND_COMPILE_NO_JUMPTABLES (1<<16)
|
||||||
|
|
||||||
|
/* this flag is set when compiler invoked during preloading in separate process */
|
||||||
|
#define ZEND_COMPILE_PRELOAD_IN_CHILD (1<<17)
|
||||||
|
|
||||||
/* The default value for CG(compiler_options) */
|
/* The default value for CG(compiler_options) */
|
||||||
#define ZEND_COMPILE_DEFAULT ZEND_COMPILE_HANDLE_OP_ARRAY
|
#define ZEND_COMPILE_DEFAULT ZEND_COMPILE_HANDLE_OP_ARRAY
|
||||||
|
|
||||||
|
|
101
ext/ffi/ffi.c
101
ext/ffi/ffi.c
|
@ -3083,15 +3083,13 @@ static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type) /* {{{ */
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
ZEND_METHOD(FFI, load) /* {{{ */
|
static zend_ffi *zend_ffi_load(const char *filename, zend_bool preload) /* {{{ */
|
||||||
{
|
{
|
||||||
zend_string *fn;
|
|
||||||
struct stat buf;
|
struct stat buf;
|
||||||
int fd;
|
int fd;
|
||||||
char *filename, *code, *code_pos, *scope_name, *lib;
|
char *code, *code_pos, *scope_name, *lib;
|
||||||
size_t code_size, scope_name_len;
|
size_t code_size, scope_name_len;
|
||||||
zend_ffi *ffi;
|
zend_ffi *ffi;
|
||||||
zend_bool preload = (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0;
|
|
||||||
DL_HANDLE handle = NULL;
|
DL_HANDLE handle = NULL;
|
||||||
zend_ffi_scope *scope = NULL;
|
zend_ffi_scope *scope = NULL;
|
||||||
zend_string *name;
|
zend_string *name;
|
||||||
|
@ -3099,19 +3097,13 @@ ZEND_METHOD(FFI, load) /* {{{ */
|
||||||
zend_ffi_tag *tag;
|
zend_ffi_tag *tag;
|
||||||
void *addr;
|
void *addr;
|
||||||
|
|
||||||
ZEND_FFI_VALIDATE_API_RESTRICTION();
|
|
||||||
ZEND_PARSE_PARAMETERS_START(1, 1)
|
|
||||||
Z_PARAM_STR(fn)
|
|
||||||
ZEND_PARSE_PARAMETERS_END();
|
|
||||||
|
|
||||||
filename = ZSTR_VAL(fn);
|
|
||||||
if (stat(filename, &buf) != 0) {
|
if (stat(filename, &buf) != 0) {
|
||||||
if (preload) {
|
if (preload) {
|
||||||
zend_error(E_WARNING, "FFI: failed pre-loading '%s', file doesn't exist", filename);
|
zend_error(E_WARNING, "FFI: failed pre-loading '%s', file doesn't exist", filename);
|
||||||
} else {
|
} else {
|
||||||
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', file doesn't exist", filename);
|
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', file doesn't exist", filename);
|
||||||
}
|
}
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((buf.st_mode & S_IFMT) != S_IFREG) {
|
if ((buf.st_mode & S_IFMT) != S_IFREG) {
|
||||||
|
@ -3120,7 +3112,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
|
||||||
} else {
|
} else {
|
||||||
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', not a regular file", filename);
|
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', not a regular file", filename);
|
||||||
}
|
}
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
code_size = buf.st_size;
|
code_size = buf.st_size;
|
||||||
|
@ -3134,7 +3126,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
|
||||||
}
|
}
|
||||||
efree(code);
|
efree(code);
|
||||||
close(fd);
|
close(fd);
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
code[code_size] = 0;
|
code[code_size] = 0;
|
||||||
|
@ -3153,7 +3145,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
|
||||||
if (!code_pos) {
|
if (!code_pos) {
|
||||||
efree(code);
|
efree(code);
|
||||||
FFI_G(persistent) = 0;
|
FFI_G(persistent) = 0;
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
code_size -= code_pos - code;
|
code_size -= code_pos - code;
|
||||||
|
|
||||||
|
@ -3318,7 +3310,11 @@ ZEND_METHOD(FFI, load) /* {{{ */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
|
if (EG(objects_store).object_buckets) {
|
||||||
|
ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
|
||||||
|
} else {
|
||||||
|
ffi = ecalloc(1, sizeof(zend_ffi));
|
||||||
|
}
|
||||||
ffi->symbols = scope->symbols;
|
ffi->symbols = scope->symbols;
|
||||||
ffi->tags = scope->tags;
|
ffi->tags = scope->tags;
|
||||||
ffi->persistent = 1;
|
ffi->persistent = 1;
|
||||||
|
@ -3333,7 +3329,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
|
||||||
FFI_G(symbols) = NULL;
|
FFI_G(symbols) = NULL;
|
||||||
FFI_G(tags) = NULL;
|
FFI_G(tags) = NULL;
|
||||||
|
|
||||||
RETURN_OBJ(&ffi->std);
|
return ffi;
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
efree(code);
|
efree(code);
|
||||||
|
@ -3348,6 +3344,30 @@ cleanup:
|
||||||
FFI_G(tags) = NULL;
|
FFI_G(tags) = NULL;
|
||||||
}
|
}
|
||||||
FFI_G(persistent) = 0;
|
FFI_G(persistent) = 0;
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
ZEND_METHOD(FFI, load) /* {{{ */
|
||||||
|
{
|
||||||
|
zend_string *fn;
|
||||||
|
zend_ffi *ffi;
|
||||||
|
|
||||||
|
ZEND_FFI_VALIDATE_API_RESTRICTION();
|
||||||
|
ZEND_PARSE_PARAMETERS_START(1, 1)
|
||||||
|
Z_PARAM_STR(fn)
|
||||||
|
ZEND_PARSE_PARAMETERS_END();
|
||||||
|
|
||||||
|
if (CG(compiler_options) & ZEND_COMPILE_PRELOAD_IN_CHILD) {
|
||||||
|
zend_throw_error(zend_ffi_exception_ce, "FFI::load() doesn't work in conjunction with \"opcache.pelaod_user\". Use \"ffi.preload\" instead.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ffi = zend_ffi_load(ZSTR_VAL(fn), (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0);
|
||||||
|
|
||||||
|
if (ffi) {
|
||||||
|
RETURN_OBJ(&ffi->std);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -4813,8 +4833,51 @@ static ZEND_INI_DISP(zend_ffi_enable_displayer_cb) /* {{{ */
|
||||||
|
|
||||||
ZEND_INI_BEGIN()
|
ZEND_INI_BEGIN()
|
||||||
ZEND_INI_ENTRY3_EX("ffi.enable", "preload", ZEND_INI_SYSTEM, OnUpdateFFIEnable, NULL, NULL, NULL, zend_ffi_enable_displayer_cb)
|
ZEND_INI_ENTRY3_EX("ffi.enable", "preload", ZEND_INI_SYSTEM, OnUpdateFFIEnable, NULL, NULL, NULL, zend_ffi_enable_displayer_cb)
|
||||||
|
STD_ZEND_INI_ENTRY("ffi.preload", NULL, ZEND_INI_SYSTEM, OnUpdateString, preload, zend_ffi_globals, ffi_globals)
|
||||||
ZEND_INI_END()
|
ZEND_INI_END()
|
||||||
|
|
||||||
|
static int zend_ffi_preload(char *preload) /* {{{ */
|
||||||
|
{
|
||||||
|
zend_ffi *ffi;
|
||||||
|
char *s = NULL, *e, *filename;
|
||||||
|
|
||||||
|
e = preload;
|
||||||
|
while (*e) {
|
||||||
|
switch (*e) {
|
||||||
|
case ZEND_PATHS_SEPARATOR:
|
||||||
|
if (s) {
|
||||||
|
filename = estrndup(s, e-s);
|
||||||
|
ffi = zend_ffi_load(filename, 1);
|
||||||
|
efree(filename);
|
||||||
|
if (!ffi) {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
efree(ffi);
|
||||||
|
s = NULL;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!s) {
|
||||||
|
s = e;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
e++;
|
||||||
|
}
|
||||||
|
if (s) {
|
||||||
|
filename = estrndup(s, e-s);
|
||||||
|
ffi = zend_ffi_load(filename, 1);
|
||||||
|
efree(filename);
|
||||||
|
if (!ffi) {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
efree(ffi);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
/* {{{ ZEND_MINIT_FUNCTION
|
/* {{{ ZEND_MINIT_FUNCTION
|
||||||
*/
|
*/
|
||||||
ZEND_MINIT_FUNCTION(ffi)
|
ZEND_MINIT_FUNCTION(ffi)
|
||||||
|
@ -4976,6 +5039,12 @@ ZEND_MINIT_FUNCTION(ffi)
|
||||||
zend_ffi_ctype_handlers.get_properties = zend_fake_get_properties;
|
zend_ffi_ctype_handlers.get_properties = zend_fake_get_properties;
|
||||||
zend_ffi_ctype_handlers.get_gc = zend_fake_get_gc;
|
zend_ffi_ctype_handlers.get_gc = zend_fake_get_gc;
|
||||||
|
|
||||||
|
if (FFI_G(preload)) {
|
||||||
|
if (zend_ffi_preload(FFI_G(preload)) != SUCCESS) {
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
|
@ -38,6 +38,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ffi)
|
||||||
HashTable types;
|
HashTable types;
|
||||||
|
|
||||||
/* preloading */
|
/* preloading */
|
||||||
|
char *preload;
|
||||||
HashTable *scopes; /* list of preloaded scopes */
|
HashTable *scopes; /* list of preloaded scopes */
|
||||||
|
|
||||||
/* callbacks */
|
/* callbacks */
|
||||||
|
|
15
ext/ffi/tests/302.phpt
Normal file
15
ext/ffi/tests/302.phpt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
--TEST--
|
||||||
|
FFI 302: FFI preloading
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once('skipif.inc'); ?>
|
||||||
|
<?php if (substr(PHP_OS, 0, 3) == 'WIN') die('skip not for Windows'); ?>
|
||||||
|
--INI--
|
||||||
|
ffi.enable=1
|
||||||
|
ffi.preload={PWD}/300.h
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$ffi = FFI::scope("TEST_300");
|
||||||
|
$ffi->printf("Hello World from %s!\n", "PHP");
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Hello World from PHP!
|
|
@ -4140,14 +4140,17 @@ static void preload_load(void)
|
||||||
if (EG(class_table)) {
|
if (EG(class_table)) {
|
||||||
EG(persistent_classes_count) = EG(class_table)->nNumUsed;
|
EG(persistent_classes_count) = EG(class_table)->nNumUsed;
|
||||||
}
|
}
|
||||||
CG(map_ptr_last) = ZCSG(map_ptr_last);
|
if (CG(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_base) = perealloc(CG(map_ptr_base), CG(map_ptr_size) * sizeof(void*), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int accel_preload(const char *config)
|
static int accel_preload(const char *config)
|
||||||
{
|
{
|
||||||
zend_file_handle file_handle;
|
zend_file_handle file_handle;
|
||||||
int ret;
|
int ret;
|
||||||
uint32_t orig_compiler_options;
|
|
||||||
char *orig_open_basedir;
|
char *orig_open_basedir;
|
||||||
size_t orig_map_ptr_last;
|
size_t orig_map_ptr_last;
|
||||||
zval *zv;
|
zval *zv;
|
||||||
|
@ -4159,14 +4162,6 @@ static int accel_preload(const char *config)
|
||||||
preload_orig_compile_file = accelerator_orig_compile_file;
|
preload_orig_compile_file = accelerator_orig_compile_file;
|
||||||
accelerator_orig_compile_file = preload_compile_file;
|
accelerator_orig_compile_file = preload_compile_file;
|
||||||
|
|
||||||
orig_compiler_options = CG(compiler_options);
|
|
||||||
CG(compiler_options) |= ZEND_COMPILE_PRELOAD;
|
|
||||||
CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
|
|
||||||
// CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
|
|
||||||
CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
|
|
||||||
CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
|
|
||||||
// CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
|
|
||||||
|
|
||||||
orig_map_ptr_last = CG(map_ptr_last);
|
orig_map_ptr_last = CG(map_ptr_last);
|
||||||
|
|
||||||
/* Compile and execute proloading script */
|
/* Compile and execute proloading script */
|
||||||
|
@ -4207,7 +4202,6 @@ static int accel_preload(const char *config)
|
||||||
ret = FAILURE;
|
ret = FAILURE;
|
||||||
} zend_end_try();
|
} zend_end_try();
|
||||||
|
|
||||||
CG(compiler_options) = orig_compiler_options;
|
|
||||||
PG(open_basedir) = orig_open_basedir;
|
PG(open_basedir) = orig_open_basedir;
|
||||||
accelerator_orig_compile_file = preload_orig_compile_file;
|
accelerator_orig_compile_file = preload_orig_compile_file;
|
||||||
ZCG(enabled) = 1;
|
ZCG(enabled) = 1;
|
||||||
|
@ -4500,6 +4494,7 @@ static int accel_finish_startup(void)
|
||||||
char *(*orig_getenv)(char *name, size_t name_len TSRMLS_DC) = sapi_module.getenv;
|
char *(*orig_getenv)(char *name, size_t name_len TSRMLS_DC) = sapi_module.getenv;
|
||||||
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
|
size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
|
||||||
void (*orig_flush)(void *server_context) = sapi_module.flush;
|
void (*orig_flush)(void *server_context) = sapi_module.flush;
|
||||||
|
uint32_t orig_compiler_options = CG(compiler_options);
|
||||||
#ifdef ZEND_SIGNALS
|
#ifdef ZEND_SIGNALS
|
||||||
zend_bool old_reset_signals = SIGG(reset);
|
zend_bool old_reset_signals = SIGG(reset);
|
||||||
#endif
|
#endif
|
||||||
|
@ -4595,6 +4590,18 @@ static int accel_finish_startup(void)
|
||||||
sapi_module.ub_write = preload_ub_write;
|
sapi_module.ub_write = preload_ub_write;
|
||||||
sapi_module.flush = preload_flush;
|
sapi_module.flush = preload_flush;
|
||||||
|
|
||||||
|
#ifndef ZEND_WIN32
|
||||||
|
if (in_child) {
|
||||||
|
CG(compiler_options) |= ZEND_COMPILE_PRELOAD_IN_CHILD;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
CG(compiler_options) |= ZEND_COMPILE_PRELOAD;
|
||||||
|
CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
|
||||||
|
CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
|
||||||
|
CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
|
||||||
|
CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
|
||||||
|
CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
|
||||||
|
|
||||||
zend_interned_strings_switch_storage(1);
|
zend_interned_strings_switch_storage(1);
|
||||||
|
|
||||||
#ifdef ZEND_SIGNALS
|
#ifdef ZEND_SIGNALS
|
||||||
|
@ -4648,6 +4655,8 @@ static int accel_finish_startup(void)
|
||||||
SIGG(reset) = old_reset_signals;
|
SIGG(reset) = old_reset_signals;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CG(compiler_options) = orig_compiler_options;
|
||||||
|
|
||||||
sapi_module.activate = orig_activate;
|
sapi_module.activate = orig_activate;
|
||||||
sapi_module.deactivate = orig_deactivate;
|
sapi_module.deactivate = orig_deactivate;
|
||||||
sapi_module.register_server_variables = orig_register_server_variables;
|
sapi_module.register_server_variables = orig_register_server_variables;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue