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
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: kentaro at ranvis dot com
New email:
PHP Version: OS:

 

 [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-2021 The PHP Group
All rights reserved.
Last updated: Mon Oct 18 05:03:33 2021 UTC