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
Have you experienced this issue?
Rate the importance of this bug to you:

 [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: Thu Oct 28 00:03:33 2021 UTC