Skip to content

Commit c727f29

Browse files
committed
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.
1 parent 7585cf6 commit c727f29

File tree

3 files changed

+57
-0
lines changed

3 files changed

+57
-0
lines changed

Diff for: NEWS

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ PHP NEWS
1313
- FFI:
1414
. Fixed bug GH-9698 (stream_wrapper_register crashes with FFI\CData).
1515
(Jakub Zelenka)
16+
. Fixed bug GH-12905 (FFI::new interacts badly with observers). (nielsdos)
1617

1718
- Hash:
1819
. Fixed bug GH-12936 (hash() function hangs endlessly if using sha512 on

Diff for: ext/ffi/ffi.c

+23
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "zend_closures.h"
2727
#include "zend_weakrefs.h"
2828
#include "main/SAPI.h"
29+
#include "zend_observer.h"
2930

3031
#include <ffi.h>
3132

@@ -5305,6 +5306,25 @@ static zend_result zend_ffi_preload(char *preload) /* {{{ */
53055306
}
53065307
/* }}} */
53075308

5309+
/* The startup code for observers adds a temporary to each function for internal use.
5310+
* The "new", "cast", and "type" functions in FFI are both static and non-static.
5311+
* Only the static versions are in the function table and the non-static versions are not.
5312+
* This means the non-static versions will be skipped by the observers startup code.
5313+
* This function fixes that by incrementing the temporary count for the non-static versions.
5314+
*/
5315+
static zend_result (*prev_zend_post_startup_cb)(void);
5316+
static zend_result ffi_fixup_temporaries(void) {
5317+
if (ZEND_OBSERVER_ENABLED) {
5318+
++zend_ffi_new_fn.T;
5319+
++zend_ffi_cast_fn.T;
5320+
++zend_ffi_type_fn.T;
5321+
}
5322+
if (prev_zend_post_startup_cb) {
5323+
return prev_zend_post_startup_cb();
5324+
}
5325+
return SUCCESS;
5326+
}
5327+
53085328
/* {{{ ZEND_MINIT_FUNCTION */
53095329
ZEND_MINIT_FUNCTION(ffi)
53105330
{
@@ -5326,6 +5346,9 @@ ZEND_MINIT_FUNCTION(ffi)
53265346
memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
53275347
zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
53285348

5349+
prev_zend_post_startup_cb = zend_post_startup_cb;
5350+
zend_post_startup_cb = ffi_fixup_temporaries;
5351+
53295352
memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
53305353
zend_ffi_handlers.get_constructor = zend_fake_get_constructor;
53315354
zend_ffi_handlers.free_obj = zend_ffi_free_obj;

Diff for: ext/ffi/tests/gh12905.phpt

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
GH-12905 (FFI::new interacts badly with observers)
3+
--EXTENSIONS--
4+
ffi
5+
zend_test
6+
--SKIPIF--
7+
<?php
8+
try {
9+
$libc = FFI::cdef("int printf(const char *format, ...);", "libc.so.6");
10+
} catch (Throwable $_) {
11+
die('skip libc.so.6 not available');
12+
}
13+
?>
14+
--INI--
15+
ffi.enable=1
16+
zend_test.observer.enabled=1
17+
zend_test.observer.observe_all=1
18+
zend_test.observer.show_return_value=0
19+
--FILE--
20+
<?php
21+
$ffi = FFI::cdef("", "libc.so.6");
22+
$ffi->new("int");
23+
?>
24+
--EXPECTF--
25+
<!-- init '%sgh12905.php' -->
26+
<file '%sgh12905.php'>
27+
<!-- init FFI::cdef() -->
28+
<FFI::cdef>
29+
</FFI::cdef>
30+
<!-- init FFI::new() -->
31+
<FFI::new>
32+
</FFI::new>
33+
</file '%sgh12905.php'>

0 commit comments

Comments
 (0)