Merge branch 'PHP-7.4'

* PHP-7.4:
  Allow loading FFI bindings through ffi.preload directive
This commit is contained in:
Dmitry Stogov 2019-10-22 17:53:24 +03:00
commit 626a5837c0
5 changed files with 124 additions and 27 deletions

View File

@ -1089,6 +1089,9 @@ END_EXTERN_C()
/* disable jumptable optimization for switch statements */
#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) */
#define ZEND_COMPILE_DEFAULT ZEND_COMPILE_HANDLE_OP_ARRAY

View File

@ -3055,15 +3055,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;
int fd;
char *filename, *code, *code_pos, *scope_name, *lib;
char *code, *code_pos, *scope_name, *lib;
size_t code_size, scope_name_len;
zend_ffi *ffi;
zend_bool preload = (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0;
DL_HANDLE handle = NULL;
zend_ffi_scope *scope = NULL;
zend_string *name;
@ -3071,19 +3069,13 @@ ZEND_METHOD(FFI, load) /* {{{ */
zend_ffi_tag *tag;
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 (preload) {
zend_error(E_WARNING, "FFI: failed pre-loading '%s', file doesn't exist", filename);
} else {
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) {
@ -3092,7 +3084,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
} else {
zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', not a regular file", filename);
}
return;
return NULL;
}
code_size = buf.st_size;
@ -3106,7 +3098,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
}
efree(code);
close(fd);
return;
return NULL;
}
close(fd);
code[code_size] = 0;
@ -3125,7 +3117,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
if (!code_pos) {
efree(code);
FFI_G(persistent) = 0;
return;
return NULL;
}
code_size -= code_pos - code;
@ -3290,7 +3282,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->tags = scope->tags;
ffi->persistent = 1;
@ -3305,7 +3301,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
FFI_G(symbols) = NULL;
FFI_G(tags) = NULL;
RETURN_OBJ(&ffi->std);
return ffi;
cleanup:
efree(code);
@ -3320,6 +3316,30 @@ cleanup:
FFI_G(tags) = NULL;
}
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);
}
}
/* }}} */
@ -4690,8 +4710,51 @@ static ZEND_INI_DISP(zend_ffi_enable_displayer_cb) /* {{{ */
ZEND_INI_BEGIN()
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()
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(ffi)
@ -4852,6 +4915,12 @@ ZEND_MINIT_FUNCTION(ffi)
zend_ffi_ctype_handlers.get_properties = zend_fake_get_properties;
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;
}
/* }}} */

View File

@ -36,6 +36,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ffi)
HashTable types;
/* preloading */
char *preload;
HashTable *scopes; /* list of preloaded scopes */
/* callbacks */

15
ext/ffi/tests/302.phpt Normal file
View 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!

View File

@ -4194,14 +4194,17 @@ static void preload_load(void)
if (EG(class_table)) {
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)
{
zend_file_handle file_handle;
int ret;
uint32_t orig_compiler_options;
char *orig_open_basedir;
size_t orig_map_ptr_last;
zval *zv;
@ -4213,14 +4216,6 @@ static int accel_preload(const char *config)
preload_orig_compile_file = accelerator_orig_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);
/* Compile and execute proloading script */
@ -4261,7 +4256,6 @@ static int accel_preload(const char *config)
ret = FAILURE;
} zend_end_try();
CG(compiler_options) = orig_compiler_options;
PG(open_basedir) = orig_open_basedir;
accelerator_orig_compile_file = preload_orig_compile_file;
ZCG(enabled) = 1;
@ -4555,6 +4549,7 @@ static int accel_finish_startup(void)
char *(*orig_getenv)(char *name, size_t name_len) = sapi_module.getenv;
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;
uint32_t orig_compiler_options = CG(compiler_options);
#ifdef ZEND_SIGNALS
zend_bool old_reset_signals = SIGG(reset);
#endif
@ -4650,6 +4645,18 @@ static int accel_finish_startup(void)
sapi_module.ub_write = preload_ub_write;
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);
#ifdef ZEND_SIGNALS
@ -4703,6 +4710,8 @@ static int accel_finish_startup(void)
SIGG(reset) = old_reset_signals;
#endif
CG(compiler_options) = orig_compiler_options;
sapi_module.activate = orig_activate;
sapi_module.deactivate = orig_deactivate;
sapi_module.register_server_variables = orig_register_server_variables;