Skip to content

Commit ecdaf83

Browse files
committed
Allow to fetch function address
2 parents 22c8345 + e902e4a commit ecdaf83

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

ext/ffi/ffi.c

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2355,7 +2355,7 @@ static zval *zend_ffi_read_var(zval *object, zval *member, int read_type, void *
23552355

23562356
if (ffi->symbols) {
23572357
sym = zend_hash_find_ptr(ffi->symbols, var_name);
2358-
if (sym && sym->kind != ZEND_FFI_SYM_VAR && sym->kind != ZEND_FFI_SYM_CONST) {
2358+
if (sym && sym->kind != ZEND_FFI_SYM_VAR && sym->kind != ZEND_FFI_SYM_CONST && sym->kind != ZEND_FFI_SYM_FUNC) {
23592359
sym = NULL;
23602360
}
23612361
}
@@ -2369,6 +2369,24 @@ static zval *zend_ffi_read_var(zval *object, zval *member, int read_type, void *
23692369

23702370
if (sym->kind == ZEND_FFI_SYM_VAR) {
23712371
zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0);
2372+
} else if (sym->kind == ZEND_FFI_SYM_FUNC) {
2373+
zend_ffi_cdata *cdata;
2374+
zend_ffi_type *new_type = emalloc(sizeof(zend_ffi_type));
2375+
2376+
new_type->kind = ZEND_FFI_TYPE_POINTER;
2377+
new_type->attr = 0;
2378+
new_type->size = sizeof(void*);
2379+
new_type->align = _Alignof(void*);
2380+
new_type->pointer.type = ZEND_FFI_TYPE(sym->type);
2381+
2382+
cdata = emalloc(sizeof(zend_ffi_cdata));
2383+
zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
2384+
cdata->std.handlers = &zend_ffi_cdata_handlers;
2385+
cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
2386+
cdata->flags = ZEND_FFI_FLAG_CONST;
2387+
cdata->ptr_holder = sym->addr;
2388+
cdata->ptr = &cdata->ptr_holder;
2389+
ZVAL_OBJ(rv, &cdata->std);
23722390
} else {
23732391
ZVAL_LONG(rv, sym->value);
23742392
}

ext/ffi/tests/101.phpt

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
--TEST--
2+
FFI 101: PHP symbols (function address)
3+
--SKIPIF--
4+
<?php require_once('skipif.inc'); ?>
5+
<?php
6+
try {
7+
FFI::cdef("extern void *zend_printf;");
8+
} catch (Throwable $e) {
9+
die('skip PHP symbols not available');
10+
}
11+
?>
12+
--INI--
13+
ffi.enable=1
14+
--FILE--
15+
<?php
16+
// Check if target supports "fastcall" calling convention
17+
try {
18+
FFI::cdef("extern size_t __attribute__((fastcall)) (*zend_printf)(const char *format);");
19+
$fastcall = "__attribute__((fastcall)) ";
20+
} catch (Throwable $e) {
21+
$fastcall = "";
22+
}
23+
$zend = FFI::cdef("
24+
const char *get_zend_version(void);
25+
//char *get_zend_version(void);
26+
extern size_t (*zend_printf)(const char *format, ...);
27+
28+
unsigned long $fastcall zend_hash_func(const char *str, size_t len);
29+
30+
void $fastcall zend_str_tolower(char *str, size_t length);
31+
32+
");
33+
$f = $zend->get_zend_version;
34+
var_dump(trim(explode("\n",$f())[0]));
35+
//var_dump(trim(FFI::string($zend->get_zend_version())));
36+
var_dump($zend->zend_printf);
37+
var_dump(($zend->zend_printf)("Hello %s!\n", "World"));
38+
39+
$f = $zend->zend_hash_func;
40+
var_dump($f("file", strlen("file")));
41+
42+
$str = $zend->new("char[16]");
43+
FFI::memcpy($str, "Hello World!", strlen("Hello World!"));
44+
$f = $zend->zend_str_tolower;
45+
$f($str, strlen("Hello World!"));
46+
var_dump(FFI::string($str));
47+
48+
?>
49+
--EXPECTF--
50+
string(%d) "Zend Engine %s"
51+
object(FFI\CData:uint%d_t(*)())#%d (1) {
52+
[0]=>
53+
object(FFI\CData:uint%d_t())#%d (0) {
54+
}
55+
}
56+
Hello World!
57+
int(13)
58+
int(%i)
59+
string(12) "hello world!"

0 commit comments

Comments
 (0)