]> granicus.if.org Git - php/commitdiff
Allow loading FFI bindings through ffi.preload directive
authorDmitry Stogov <dmitry@zend.com>
Tue, 22 Oct 2019 14:52:56 +0000 (17:52 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 22 Oct 2019 14:52:56 +0000 (17:52 +0300)
Zend/zend_compile.h
ext/ffi/ffi.c
ext/ffi/php_ffi.h
ext/ffi/tests/302.phpt [new file with mode: 0644]
ext/opcache/ZendAccelerator.c

index 499d0d64b6413e9112f3930aa8a3370e328f3c29..c21554e4641e59d9d24d9aae7444b82289e7e601 100644 (file)
@@ -1094,6 +1094,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
 
index 1edba157a171cb33b75d8eeb4f84d26b6fead4ab..4b7144e11cccbe7dddbdbd51d9568e780308e249 100644 (file)
@@ -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;
        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;
@@ -3099,19 +3097,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) {
@@ -3120,7 +3112,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;
@@ -3134,7 +3126,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
                }
                efree(code);
                close(fd);
-               return;
+               return NULL;
        }
        close(fd);
        code[code_size] = 0;
@@ -3153,7 +3145,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
        if (!code_pos) {
                efree(code);
                FFI_G(persistent) = 0;
-               return;
+               return NULL;
        }
        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->tags = scope->tags;
                ffi->persistent = 1;
@@ -3333,7 +3329,7 @@ ZEND_METHOD(FFI, load) /* {{{ */
        FFI_G(symbols) = NULL;
        FFI_G(tags) = NULL;
 
-       RETURN_OBJ(&ffi->std);
+       return ffi;
 
 cleanup:
        efree(code);
@@ -3348,6 +3344,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);
+       }
 }
 /* }}} */
 
@@ -4813,8 +4833,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)
@@ -4976,6 +5039,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;
 }
 /* }}} */
index 0f511fccf05cb033bae9f6f27231671b4566e647..b9f01d6e96f48bb024995e399bfc72519457e9ed 100644 (file)
@@ -38,6 +38,7 @@ ZEND_BEGIN_MODULE_GLOBALS(ffi)
        HashTable types;
 
        /* preloading */
+       char *preload;
        HashTable *scopes;           /* list of preloaded scopes */
 
        /* callbacks */
diff --git a/ext/ffi/tests/302.phpt b/ext/ffi/tests/302.phpt
new file mode 100644 (file)
index 0000000..cb0d73d
--- /dev/null
@@ -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!
index 636058dd087532b8e86ce50dd65c6803d6807f25..704e1c38d9b75dc02f089a44160cd5cc04ff09ac 100644 (file)
@@ -4140,14 +4140,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;
@@ -4159,14 +4162,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 */
@@ -4207,7 +4202,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;
@@ -4500,6 +4494,7 @@ static int accel_finish_startup(void)
                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;
                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
@@ -4595,6 +4590,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
@@ -4648,6 +4655,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;