Bug #79144 [Nab]: FFI call exported function without referencing it
| From: | requinix@php.net | Date: | Mon, 20 Jan 2020 22:53:29 +0000 |
| Subject: | Bug #79144 [Nab]: FFI call exported function without referencing it | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-225021@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=79144&edit=1
ID: 79144
Updated by: requinix@php.net
Reported by: php at tim dot ainfach dot de
Summary: FFI call exported function without referencing it
Status: Not a bug
Type: Bug
Package: *Extensibility Functions
Operating System: OSX 10.14.6
PHP Version: 7.4.1
Block user comment: N
Private report: N
New Comment:
In other other ticket,
> struct bug79096 bug79096(void);
bug79096 is defined as a function.
In this ticket,
> extern zend_write_func_t zend_write;
zend_write is defined as a variable. Because it actually is a variable. Zend Engine stuff.
If you want to call "the zend_write function" you have to find out what the actual
underlying function is. I'll spare you the legwork and tell you that (normally) it is
php_output_write, implemented in main/output.c.
So
$zend = FFI::cdef("
int php_output_write(const char *str, size_t str_length);
");
$zend->php_output_write("aaa", 3);
Of course, doing it this way doesn't get you the actual zend_write "function". It
gets you php_output_write. But maybe that's fine for you.
Previous Comments:
------------------------------------------------------------------------
[2020-01-20 22:02:33] php at tim dot ainfach dot de
thank you for the explanation.
it feels very inconsitent because for example if i export a function from C like here https://bugs.php.net/bug.php?id=79125 i am able fo
call $ffi->FUNCTION() directly.
there is a reason why different approaches were chosen here?
------------------------------------------------------------------------
[2020-01-20 21:53:53] requinix@php.net
$zend->zend_write is a property, not a method. It's as if you wrote
$zend = new stdClass();
$zend->zend_write = function(string $str, int $str_length) { ... };
------------------------------------------------------------------------
[2020-01-20 21:27:50] php at tim dot ainfach dot de
Description:
------------
when using a function that is exported by php (ZEND_API) it's not possible to call the function
directly. You've to create a reference to the function and then it is possible to call it.
i would expect that it is possible to call the function directly.
these are working fine:
$a = $zend->zend_write; $a("aaa", 3);
($zend->zend_write)("aaa", 3);
(clone $zend->zend_write)("aaa", 3);
this doesn't work -> Attempt to call undefined C function 'zend_write'
$zend->zend_write("aaa", 3);
$a = [$zend, 'zend_write']; $a("aaa", 3);
Test script:
---------------
public static function assertObSame(string $expected, callable $cb)
{
ob_start();
$cb();
$res = ob_get_contents();
ob_end_clean();
static::assertSame($expected, $res);
}
public function testReturnU64()
{
$zend = FFI::cdef("
typedef int (*zend_write_func_t)(const char *str, size_t str_length);
extern zend_write_func_t zend_write;
");
static::assertObSame('aaa', function() use ($zend) { $a = $zend->zend_write;
$a("aaa", 3); });
static::assertObSame('aaa', function() use ($zend) {
($zend->zend_write)("aaa", 3); });
static::assertObSame('aaa', function() use ($zend) { (clone
$zend->zend_write)("aaa", 3); });
// does not work -> end up in a Attempt to call undefined C function
'zend_write'
static::assertObSame('aaa', function() use ($zend) {
$zend->zend_write("aaa", 3); });
static::assertObSame('aaa', function() use ($zend) { $a = [$zend,
'zend_write']; $a("aaa", 3); });
}
Expected result:
----------------
all ways to call zend_write should give the same result (pass the assertion).
Actual result:
--------------
FFI\Exception: Attempt to call undefined C function 'zend_write'
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=79144&edit=1