Fix GH-12905: FFI::new interacts badly with observers

Because these functions are copied and not properly registered (which we
can't), the observer code doesn't add the temporaries on startup.
Add them via a callback during startup.

Closes GH-12906.
This commit is contained in:
Niels Dossche 2023-12-08 17:44:03 +01:00
parent 7585cf6952
commit c727f29942
3 changed files with 57 additions and 0 deletions

1
NEWS
View File

@ -13,6 +13,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

View File

@ -26,6 +26,7 @@
#include "zend_closures.h"
#include "zend_weakrefs.h"
#include "main/SAPI.h"
#include "zend_observer.h"
#include <ffi.h>
@ -5305,6 +5306,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)
{
@ -5326,6 +5346,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;

View File

@ -0,0 +1,33 @@
--TEST--
GH-12905 (FFI::new interacts badly with observers)
--EXTENSIONS--
ffi
zend_test
--SKIPIF--
<?php
try {
$libc = FFI::cdef("int printf(const char *format, ...);", "libc.so.6");
} catch (Throwable $_) {
die('skip libc.so.6 not available');
}
?>
--INI--
ffi.enable=1
zend_test.observer.enabled=1
zend_test.observer.observe_all=1
zend_test.observer.show_return_value=0
--FILE--
<?php
$ffi = FFI::cdef("", "libc.so.6");
$ffi->new("int");
?>
--EXPECTF--
<!-- init '%sgh12905.php' -->
<file '%sgh12905.php'>
<!-- init FFI::cdef() -->
<FFI::cdef>
</FFI::cdef>
<!-- init FFI::new() -->
<FFI::new>
</FFI::new>
</file '%sgh12905.php'>