-
Notifications
You must be signed in to change notification settings - Fork 7.9k
endianness issue with FFI (ext/ffi/tests/gh11934.phpt
)
#16013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
For instance, the following looks fishy: Lines 787 to 790 in ba748e7
|
I think reading and writing to the cdata is OK; if I do i.e. <?php
echo "--- Callback return type ---\n";
$ffi = FFI::cdef('
typedef uint32_t (*test_callback)();
typedef struct {
test_callback call_me;
} my_struct;
');
$struct = $ffi->new('my_struct');
$struct->call_me = function () use ($ffi) {
$int = $ffi->new('uint32_t');
$int->cdata = 42;
var_dump($int->cdata);
return $int;
};
var_dump(($struct->call_me)()); ...the |
Oh, found it. Still holds on Linux, which makes it easier to debug. |
the classic |
I think the problem is types smaller than machine register size are widened to the size of registers; Since you can i.e. be working with actual 32-bit stuff referenced by pointer for a cdata and that works fine, I'm suspecting the fix might be to change the return FFI type before calling |
And most annoyingly is that almost none of the core developers have access to big endian machines. A similar problem already exists for AArch64, but less problematic than big endian platforms. |
I can provide access to a BE machine for developers. I'm also going to use it for CI, but it should have plenty of spare resources. |
I have a preliminary patch that makes all tests pass and fixes support for bool, char, etc as well on big endian: https://gist.github.com/nielsdos/b9b5cae93caa5c485e9b259dc3a43600 |
I just noticed this issue myself, and was about to file another dupe bug report; glad I searched (I see there were plenty of other mentions of this issue even beyond this). What a coincidence it's being worked on right now after all this time. :) Thank you!! The patch looks a little complicated but I failed to notice there were issues with input parameters as well -- must have got lucky with the parameter types or values of my calls. I should look into it more. On the return value issue, I patched
Which seemed to be sufficient to make everything function correctly in my PHP scripts in practice. |
Interesting, thanks for sharing!
Right, this would work too I suppose. I just added a macro and integrated it in the cases where narrowing occurs, that way we don't end up with a special code path. Simplification is probably possible though but refactoring how the switch is done is something for the master branch. |
This is just extra code added on in front, not refactoring or touching the preexisting switch in any way, since that was and remains correct for the I see now the rest of your patch, and all that extensive surgery (to I don't immediately see a way to make things simpler there, only noting that maybe you could find a way to make use of the fact that libffi typedefs, along with the always unsigned |
The FFI call return values follow widening rules. We must widen to `ffi_arg` in the case we're handling a return value for types shorter than the machine width. From http://www.chiark.greenend.org.uk/doc/libffi-dev/html/The-Closure-API.html: > In most cases, ret points to an object of exactly the size of the type specified when cif was constructed. > However, integral types narrower than the system register size are widened. > In these cases your program may assume that ret points to an ffi_arg object. If we don't do this, we get wrong values when reading the return values.
The FFI call return values follow widening rules. We must widen to `ffi_arg` in the case we're handling a return value for types shorter than the machine width. From http://www.chiark.greenend.org.uk/doc/libffi-dev/html/The-Closure-API.html: > In most cases, ret points to an object of exactly the size of the type specified when cif was constructed. > However, integral types narrower than the system register size are widened. > In these cases your program may assume that ret points to an ffi_arg object. If we don't do this, we get wrong values when reading the return values. Co-authored-by: Dmitry Stogov <[email protected]>
* PHP-8.3: Fix GH-16013 and bug #80857: Big endian issues
* PHP-8.4: Fix GH-16013 and bug #80857: Big endian issues
The FFI call return values follow widening rules. We must widen to `ffi_arg` in the case we're handling a return value for types shorter than the machine width. From http://www.chiark.greenend.org.uk/doc/libffi-dev/html/The-Closure-API.html: > In most cases, ret points to an object of exactly the size of the type specified when cif was constructed. > However, integral types narrower than the system register size are widened. > In these cases your program may assume that ret points to an ffi_arg object. If we don't do this, we get wrong values when reading the return values. Closes phpGH-17255. Co-authored-by: Dmitry Stogov <[email protected]>
Description
Caught this when provisioning a big endian box for CI.
diff output on test:
The relevant part of that test:
Not familiar with FFI, so haven't looked into it yet, but making a note.
PHP Version
PHP 8.4.0-DEV
Operating System
Gentoo/ppc64
The text was updated successfully, but these errors were encountered: