diff --git a/NEWS b/NEWS index 2c32df5389f..52d9b956afa 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,7 @@ PHP NEWS - FFI: . Fixed bug GH-9698 (stream_wrapper_register crashes with FFI\CData). (Jakub Zelenka) + . Fixed bug GH-12905 (FFI::new interacts badly with observers). (nielsdos) - Hash: . Fixed bug GH-12936 (hash() function hangs endlessly if using sha512 on diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c index 7c7c992bb26..b9ae159574c 100644 --- a/ext/ffi/ffi.c +++ b/ext/ffi/ffi.c @@ -26,6 +26,7 @@ #include "zend_closures.h" #include "zend_weakrefs.h" #include "main/SAPI.h" +#include "zend_observer.h" #include @@ -5373,6 +5374,25 @@ static zend_result zend_ffi_preload(char *preload) /* {{{ */ } /* }}} */ +/* The startup code for observers adds a temporary to each function for internal use. + * The "new", "cast", and "type" functions in FFI are both static and non-static. + * Only the static versions are in the function table and the non-static versions are not. + * This means the non-static versions will be skipped by the observers startup code. + * This function fixes that by incrementing the temporary count for the non-static versions. + */ +static zend_result (*prev_zend_post_startup_cb)(void); +static zend_result ffi_fixup_temporaries(void) { + if (ZEND_OBSERVER_ENABLED) { + ++zend_ffi_new_fn.T; + ++zend_ffi_cast_fn.T; + ++zend_ffi_type_fn.T; + } + if (prev_zend_post_startup_cb) { + return prev_zend_post_startup_cb(); + } + return SUCCESS; +} + /* {{{ ZEND_MINIT_FUNCTION */ ZEND_MINIT_FUNCTION(ffi) { @@ -5395,6 +5415,9 @@ ZEND_MINIT_FUNCTION(ffi) memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function)); zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC; + prev_zend_post_startup_cb = zend_post_startup_cb; + zend_post_startup_cb = ffi_fixup_temporaries; + memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); zend_ffi_handlers.get_constructor = zend_fake_get_constructor; zend_ffi_handlers.free_obj = zend_ffi_free_obj; diff --git a/ext/ffi/tests/gh12905.phpt b/ext/ffi/tests/gh12905.phpt new file mode 100644 index 00000000000..adcc32db290 --- /dev/null +++ b/ext/ffi/tests/gh12905.phpt @@ -0,0 +1,33 @@ +--TEST-- +GH-12905 (FFI::new interacts badly with observers) +--EXTENSIONS-- +ffi +zend_test +--SKIPIF-- + +--INI-- +ffi.enable=1 +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_return_value=0 +--FILE-- +new("int"); +?> +--EXPECTF-- + + + + + + + + +