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 phpGH-16351.
1 parent 9504fcf commit db991bc

File tree

17 files changed

+57
-135
lines changed

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--

0 commit comments

Comments
 (0)