Skip to content

Commit db991bc

Browse files
committed
FFI: support symbol lookup without specifying lib on Windows
This works similar to `dlsym(RTLD_DEFAULT, …)` with the caveat that symbols on Windows may not be unique, and are usually qualified by the module they are exported from. That means that wrong symbols may be fetched, potentially causing serious issues; therefore this usage is not recommended for production purposes, but is a nice simplification for quick experiments and the ext/ffi test suite. Closes GH-16351.
1 parent 9504fcf commit db991bc

17 files changed

+57
-135
lines changed

UPGRADING

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,11 @@ PHP 8.5 UPGRADE NOTES
116116
PHP_RELEASE_VERSION are now always numbers. Previously, they have been
117117
strings for buildconf builds.
118118

119+
* FFI:
120+
. It is no longer necessary to specify the library when using FFI::cdef()
121+
and FFI::load(). However, this convenience feature should not be used in
122+
production.
123+
119124
========================================
120125
13. Other Changes
121126
========================================

ext/ffi/ffi.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,6 +2974,40 @@ static zend_always_inline bool zend_ffi_validate_api_restriction(zend_execute_da
29742974
} \
29752975
} while (0)
29762976

2977+
#ifdef PHP_WIN32
2978+
# ifndef DWORD_MAX
2979+
# define DWORD_MAX ULONG_MAX
2980+
# endif
2981+
# define NUM_MODULES 1024
2982+
/* A rough approximation of dlysm(RTLD_DEFAULT) */
2983+
static void *dlsym_loaded(char *symbol)
2984+
{
2985+
HMODULE modules_static[NUM_MODULES], *modules = modules_static;
2986+
DWORD num = NUM_MODULES, i;
2987+
void * addr;
2988+
if (!EnumProcessModules(GetCurrentProcess(), modules, num * sizeof(HMODULE), &num)) {
2989+
return NULL;
2990+
}
2991+
if (num >= NUM_MODULES && num <= DWORD_MAX / sizeof(HMODULE)) {
2992+
modules = emalloc(num *sizeof(HMODULE));
2993+
if (!EnumProcessModules(GetCurrentProcess(), modules, num * sizeof(HMODULE), &num)) {
2994+
efree(modules);
2995+
return NULL;
2996+
}
2997+
}
2998+
for (i = 0; i < num; i++) {
2999+
addr = GetProcAddress(modules[i], symbol);
3000+
if (addr != NULL) break;
3001+
}
3002+
if (modules != modules_static) {
3003+
efree(modules);
3004+
}
3005+
return addr;
3006+
}
3007+
# undef DL_FETCH_SYMBOL
3008+
# define DL_FETCH_SYMBOL(h, s) (h == NULL ? dlsym_loaded(s) : GetProcAddress(h, s))
3009+
#endif
3010+
29773011
ZEND_METHOD(FFI, cdef) /* {{{ */
29783012
{
29793013
zend_string *code = NULL;

ext/ffi/tests/100.phpt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ FFI 100: PHP symbols
33
--EXTENSIONS--
44
ffi
55
--SKIPIF--
6-
<?php require_once('utils.inc'); ?>
76
<?php
87
try {
9-
ffi_cdef("extern void *zend_printf;", ffi_get_php_dll_name());
8+
FFI::cdef("extern void *zend_printf;");
109
} catch (Throwable $e) {
1110
die('skip PHP symbols not available');
1211
}
@@ -17,7 +16,7 @@ ffi.enable=1
1716
<?php
1817
require_once('utils.inc');
1918
$fastcall = ffi_get_fastcall_specifier();
20-
$zend = ffi_cdef("
19+
$zend = FFI::cdef("
2120
const char *get_zend_version(void);
2221
//char *get_zend_version(void);
2322
extern size_t (*zend_printf)(const char *format, ...);
@@ -26,7 +25,7 @@ $zend = ffi_cdef("
2625
2726
void $fastcall zend_str_tolower(char *str, size_t length);
2827
29-
", ffi_get_php_dll_name());
28+
");
3029
var_dump(trim(explode("\n",$zend->get_zend_version())[0]));
3130
//var_dump(trim(FFI::string($zend->get_zend_version())));
3231
var_dump($zend->zend_printf);

ext/ffi/tests/101.phpt

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ FFI 101: PHP symbols (function address)
33
--EXTENSIONS--
44
ffi
55
--SKIPIF--
6-
<?php require_once('utils.inc'); ?>
76
<?php
87
try {
9-
ffi_cdef("extern void *zend_printf;", ffi_get_php_dll_name());
8+
FFI::cdef("extern void *zend_printf;");
109
} catch (Throwable $e) {
1110
die('skip PHP symbols not available');
1211
}
@@ -17,7 +16,7 @@ ffi.enable=1
1716
<?php
1817
require_once('utils.inc');
1918
$fastcall = ffi_get_fastcall_specifier();
20-
$zend = ffi_cdef("
19+
$zend = FFI::cdef("
2120
const char *get_zend_version(void);
2221
//char *get_zend_version(void);
2322
extern size_t (*zend_printf)(const char *format, ...);
@@ -26,7 +25,7 @@ $zend = ffi_cdef("
2625
2726
void $fastcall zend_str_tolower(char *str, size_t length);
2827
29-
", ffi_get_php_dll_name());
28+
");
3029
$f = $zend->get_zend_version;
3130
var_dump(trim(explode("\n",$f())[0]));
3231
//var_dump(trim(FFI::string($zend->get_zend_version())));

ext/ffi/tests/200.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ ffi
66
<?php require_once('utils.inc'); ?>
77
<?php
88
try {
9-
FFI::cdef("void* zend_write;", ffi_get_php_dll_name());
9+
FFI::cdef("void* zend_write;");
1010
} catch (Throwable $e) {
1111
die('skip PHP symbols not available');
1212
}
@@ -20,7 +20,7 @@ require_once('utils.inc');
2020
$zend = FFI::cdef("
2121
typedef size_t (*zend_write_func_t)(const char *str, size_t str_length);
2222
extern zend_write_func_t zend_write;
23-
", ffi_get_php_dll_name());
23+
");
2424

2525
echo "Hello World!\n";
2626

ext/ffi/tests/300-win32.h.in

Lines changed: 0 additions & 4 deletions
This file was deleted.

ext/ffi/tests/301-win32.phpt

Lines changed: 0 additions & 29 deletions
This file was deleted.

ext/ffi/tests/301.phpt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
FFI 301: FFI loading
33
--EXTENSIONS--
44
ffi
5-
--SKIPIF--
6-
<?php if (substr(PHP_OS, 0, 3) == 'WIN') die('skip not for Windows'); ?>
75
--INI--
86
ffi.enable=1
97
--FILE--

ext/ffi/tests/bug77632b.phpt

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ Bug #77632 (FFI function pointers with variadics)
44
ffi
55
--SKIPIF--
66
<?php
7-
require_once('utils.inc');
87
try {
9-
FFI::cdef("extern void *zend_printf;", ffi_get_php_dll_name());
8+
FFI::cdef("extern void *zend_printf;");
109
} catch (Throwable $_) {
1110
die('skip PHP symbols not available');
1211
}
@@ -15,8 +14,7 @@ try {
1514
ffi.enable=1
1615
--FILE--
1716
<?php
18-
require_once('utils.inc');
19-
$libc = FFI::cdef("extern size_t (*zend_printf)(const char *format, ...);", ffi_get_php_dll_name());
17+
$libc = FFI::cdef("extern size_t (*zend_printf)(const char *format, ...);");
2018
$args = ["test from zend_printf\n"];
2119
($libc->zend_printf)(...$args);
2220
$args2 = ["Hello, %s from zend_printf\n", "world"];

ext/ffi/tests/bug78714.phpt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ ffi
66
ffi.enable=1
77
--FILE--
88
<?php
9-
require_once('utils.inc');
109
$def = 'char * __cdecl get_zend_version(void);';
11-
$ffi = ffi_cdef($def, ffi_get_php_dll_name());
10+
$ffi = FFI::cdef($def);
1211
echo substr(FFI::string($ffi->get_zend_version()), 0, 4) . "\n";
1312
?>
1413
--EXPECT--

ext/ffi/tests/bug79096.phpt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ ffi
55
zend_test
66
--FILE--
77
<?php
8-
require_once('utils.inc');
98
$header = <<<HEADER
109
struct bug79096 {
1110
uint64_t a;
@@ -15,16 +14,7 @@ struct bug79096 {
1514
struct bug79096 bug79096(void);
1615
HEADER;
1716

18-
if (PHP_OS_FAMILY !== 'Windows') {
19-
$ffi = FFI::cdef($header);
20-
} else {
21-
try {
22-
$ffi = FFI::cdef($header, 'php_zend_test.dll');
23-
} catch (FFI\Exception $ex) {
24-
$ffi = FFI::cdef($header, ffi_get_php_dll_name());
25-
}
26-
}
27-
17+
$ffi = FFI::cdef($header);
2818
$struct = $ffi->bug79096();
2919
var_dump($struct);
3020
?>

ext/ffi/tests/bug79177.phpt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,12 @@ ffi
55
zend_test
66
--FILE--
77
<?php
8-
require_once __DIR__ . '/utils.inc';
98
$header = <<<HEADER
109
extern int *(*bug79177_cb)(void);
1110
void bug79177(void);
1211
HEADER;
1312

14-
if (PHP_OS_FAMILY !== 'Windows') {
15-
$ffi = FFI::cdef($header);
16-
} else {
17-
try {
18-
$ffi = FFI::cdef($header, 'php_zend_test.dll');
19-
} catch (FFI\Exception $ex) {
20-
$ffi = FFI::cdef($header, ffi_get_php_dll_name());
21-
}
22-
}
23-
13+
$ffi = FFI::cdef($header);
2414
$ffi->bug79177_cb = function() {
2515
throw new \RuntimeException('Not allowed');
2616
};

ext/ffi/tests/bug79532.phpt

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,11 @@ ffi
55
zend_test
66
--FILE--
77
<?php
8-
require_once('utils.inc');
9-
108
$header = <<<HEADER
119
void bug79532(off_t *array, size_t elems);
1210
HEADER;
1311

14-
if (PHP_OS_FAMILY !== 'Windows') {
15-
$ffi = FFI::cdef($header);
16-
} else {
17-
try {
18-
$ffi = FFI::cdef($header, 'php_zend_test.dll');
19-
} catch (FFI\Exception $ex) {
20-
$ffi = FFI::cdef($header, ffi_get_php_dll_name());
21-
}
22-
}
23-
12+
$ffi = FFI::cdef($header);
2413
$array = FFI::cdef()->new("off_t[3]");
2514
$ffi->bug79532($array, 3);
2615
var_dump($array);

ext/ffi/tests/bug80847.phpt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ if (PHP_OS_FAMILY == 'Windows' && ((1 << 31) > 0)) die('xfail libffi doesn\'t pr
99
?>
1010
--FILE--
1111
<?php
12-
require_once('utils.inc');
1312
$header = <<<HEADER
1413
typedef struct bug80847_01 {
1514
uint64_t b;
@@ -23,15 +22,7 @@ $header = <<<HEADER
2322
bug80847_02 ffi_bug80847(bug80847_02 s);
2423
HEADER;
2524

26-
if (PHP_OS_FAMILY !== 'Windows') {
27-
$ffi = FFI::cdef($header);
28-
} else {
29-
try {
30-
$ffi = FFI::cdef($header, 'php_zend_test.dll');
31-
} catch (FFI\Exception $ex) {
32-
$ffi = FFI::cdef($header, ffi_get_php_dll_name());
33-
}
34-
}
25+
$ffi = FFI::cdef($header);
3526
$x = $ffi->new('bug80847_02');
3627
$x->a->b = 42;
3728
$x->a->c = 42.5;

ext/ffi/tests/bug_gh9090.phpt

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ zend_test
66
--FILE--
77
<?php
88

9-
require_once 'utils.inc';
109
$h = <<<'EOD'
1110
void (*bug_gh9090_void_none_ptr)();
1211
void (*bug_gh9090_void_int_char_ptr)(int, char *);
@@ -19,15 +18,7 @@ void bug_gh9090_void_int_char(int i, char *s);
1918
void bug_gh9090_void_int_char_var(int i, char *fmt, ...);
2019
EOD;
2120

22-
if (PHP_OS_FAMILY !== 'Windows') {
23-
$ffi = FFI::cdef($h);
24-
} else {
25-
try {
26-
$ffi = FFI::cdef($h, 'php_zend_test.dll');
27-
} catch (FFI\Exception $ex) {
28-
$ffi = FFI::cdef($h, ffi_get_php_dll_name());
29-
}
30-
}
21+
$ffi = FFI::cdef($h);
3122

3223
$func_ptrs = [
3324
'bug_gh9090_void_none_ptr',

ext/ffi/tests/gh11934b.phpt

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,11 @@ ffi
55
zend_test
66
--FILE--
77
<?php
8-
require_once __DIR__ . '/utils.inc';
98
$header = <<<HEADER
109
extern int gh11934b_ffi_var_test_cdata;
1110
HEADER;
1211

13-
if (PHP_OS_FAMILY !== 'Windows') {
14-
$ffi = FFI::cdef($header);
15-
} else {
16-
try {
17-
$ffi = FFI::cdef($header, 'php_zend_test.dll');
18-
} catch (FFI\Exception $ex) {
19-
$ffi = FFI::cdef($header, ffi_get_php_dll_name());
20-
}
21-
}
22-
12+
$ffi = FFI::cdef($header);
2313
$ffi->gh11934b_ffi_var_test_cdata->cdata = 2;
2414
var_dump($ffi->gh11934b_ffi_var_test_cdata);
2515
$source = $ffi->new('int');

ext/ffi/tests/utils.inc

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,10 @@
11
<?php
22

3-
function ffi_cdef($code, $lib)
4-
{
5-
if (isset($lib)) {
6-
return FFI::cdef($code, $lib);
7-
} else {
8-
return FFI::cdef($code);
9-
}
10-
}
11-
12-
function ffi_get_php_dll_name()
13-
{
14-
if (PHP_OS_FAMILY === 'Windows') {
15-
return "php" . PHP_MAJOR_VERSION . (PHP_ZTS ? "ts" : "") . (PHP_DEBUG ? "_debug" : "") . ".dll";
16-
} else {
17-
return null;
18-
}
19-
}
20-
213
function ffi_get_fastcall_specifier()
224
{
235
foreach (['__attribute__((fastcall))', '__fastcall', '__vectorcall'] as $spec) {
246
try {
25-
ffi_cdef("extern size_t $spec zend_list_insert(void *ptr, int type);", ffi_get_php_dll_name());
7+
FFI::cdef("extern size_t $spec zend_list_insert(void *ptr, int type);");
268
return "$spec ";
279
} catch (Throwable $e) {}
2810
}

0 commit comments

Comments
 (0)