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
 [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

Pull Requests

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 Nov 21 22:01:28 2024 UTC