php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #79066 Add interface to get memory address of FFI\CData
Submitted: 2020-01-05 07:20 UTC Modified: 2021-09-16 21:23 UTC
From: kentaro at ranvis dot com Assigned:
Status: Open Package: FFI (PECL)
PHP Version: 7.4.1 OS:
Private report: No CVE-ID: None
View Add Comment Developer Edit
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please — but make sure to vote on the bug!
Your email address:
MUST BE VALID
Solve the problem:
40 - 13 = ?
Subscribe to this entry?

 
 [2020-01-05 07:20 UTC] kentaro at ranvis dot com
Description:
------------
External libraries sometimes allow/require their clients to supply custom memory allocators so that they can behave nicely with the client applications.
When using such libraries in PHP FFI world, custom free() must iterate through malloc()ed memory one-by-one, comparing FFI\Cdata using == operator (to my knowledge):

$someLibMemMgmtStruct->malloc = function (int $size) use (&$memList) {
    $mem = $ffi->new("char[$size]");
    $ptr = FFI::addr($mem);
    $memList[] = [$ptr, $size, $mem];
    return $ptr;
};
$someLibMemMgmtStruct->free = function (FFI\Cdata $ptr) use (&$memList) {
    for ($i = count($memList); --$i >= 0; ) {
        if ($ptr == $memList[$i][0]) {
            array_splice($memList, $i, 1);
            return;
        }
    }
};

So it would be really helpful if FFI\Cdata has an interface to get a unique ID (e.g. memory address,) so that that ID can be used as a key when malloc() is called.

$someLibMemMgmtStruct->malloc = function (int $size) use (&$memList) {
    $mem = $ffi->new("char[$size]");
    $ptr = FFI::addr($mem);
    $memList[FFI::id($ptr)] = [$ptr, $size, $mem];
    return $ptr;
};
$someLibMemMgmtStruct->free = function (FFI\Cdata $ptr) use (&$memList) {
    unset($memList[FFI::id($ptr)]);
};

As another way of implementation, I considered of prepending an extra info when malloc()ed. But FFI\Cdata didn't like negative offset to be referenced...


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-01-06 09:23 UTC] kentaro at ranvis dot com
Update: I had missed the doc saying FFI\Cdata pointer address can be added/subtracted.
So what I wanted to do can be achieved like the below:

malloc:
 $mem = FFI::new("struct { int64_t id, size; char data[$size]; }");
 $ptr = FFI::addr($fragment->data);

free:
 $int64Align = FFI::alignof(FFI::type('int64_t'));
 $charAlign = FFI::alignof(FFI::type('char'));
 $offsetOfData = $int64Align * 2 + (($charAlign - ($int64Align * 2) % $charAlign) % $charAlign);
 $mem = FFI::cast('struct { int64_t id, size; } *', FFI::cast('char *', $ptr) - $offsetOfData);

Not as simple as I had expected for lack of FFI::offsetof() in this case.
 [2021-09-16 21:23 UTC] cmb@php.net
-Package: ffi +Package: FFI
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Apr 25 09:01:29 2024 UTC