php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79144 FFI call exported function without referencing it
Submitted: 2020-01-20 21:27 UTC Modified: 2020-01-20 22:53 UTC
From: php at tim dot ainfach dot de Assigned:
Status: Not a bug Package: *Extensibility Functions
PHP Version: 7.4.1 OS: OSX 10.14.6
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: php at tim dot ainfach dot de
New email:
PHP Version: OS:

 

 [2020-01-20 21:27 UTC] 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'

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-01-20 21:53 UTC] requinix@php.net
-Status: Open +Status: Not a bug
 [2020-01-20 21:53 UTC] 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 22:02 UTC] 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 22:53 UTC] requinix@php.net
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.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Tue May 13 07:01:26 2025 UTC