|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
[2020-02-28 21:52 UTC] jprofic at yandex dot ru
Description:
------------
There is no way to FFI::cast() an opaque void* pointer to any scalar type (like intptr_t) so that its value can be compared to some constant (e.g. HANDLE returned by Win32 CreateFileW() call and INVALID_POINTER_VALUE = -1). Everything I tried just crashed PHP.
There are workarounds. Doing FFI::cast('void*', -1) and comparing them both as void* seems to work (“seems” because I haven't managed to subtract two pointers, but it's another tale), however it can't be a class constant. Also using FFI::memcpy(FFI:new('intptr_t'), FFI::addr(FFICData:void*))) seems to work, but the additional FFI::addr() call is required to prevent PHP from crashing as well.
Test script:
---------------
php -r "var_dump(ffi::cast('intptr_t', ffi::cast('void*', -1)));"
Expected result:
----------------
No crash and output similar to:
object(FFICData:int64_t)#1 (1) {
["cdata"]=>
int(-1)
}
Actual result:
--------------
Crash and no output.
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Sat Oct 25 07:00:02 2025 UTC |
Is there any particular reason why you don't use an intprt_t in the first place? ffi::cast('intptr_t', -1)I can't declare HANDLE as intptr_t because there are Win32 API calls that treat HANDLE as real pointers (LocalFree() comes to mind). If you meant my example, then the "ffi::cast('void*', -1)" part is emulating what I'm getting from for example CreateFileW() on error. And the rest is the culprit in the reason of this bug report. Moreover I thinks it's kinda dangerous to automatically dereference any pointer, especially the void* ones: http://git.php.net/?p=php-src.git;a=blob;f=ext/ffi/ffi.c;h=0696512342ea2ad28ca0c7b3cbdb12c87baded6e;hb=HEAD#l3861Am I reading C wrong then? Doesn't “*(void**)ptr” mean cast “ptr” to “(void**)” and then dereference it to “void*”? Or is the storage method in ffi slightly more complicated than it looks at the first glance? Hm, var_dump()'ing ffi::cast('void*', -1) produces strange and unintuitive result: object(FFI\CData:void*)#1 (1) { [0]=> int(-1) } And var_dump()'ing ffi::cast('void*', -1)[0] is even funnier: object(FFI\CData:void)#2 (1) { ["cdata"]=> *RECURSION* } Although I think I'm starting to get why it is so. Yes, I'm currently comparing two ffi\CData:void* objects and it works. Still I would prefer to have the same behaviour as present in C in regard of casting and other pointer usage to prevent any possible misunderstanding, just keeping in mind that ffi\CData object itself is a kind of pointer. Also I don't think that having a special case for intptr_t will help as at first I was trying all types of integers (and was surprised that wchar_t wasn't supported). To sum it up, I still don't think PHP should crash in my test script, and maybe there should be less magic involved in handling pointers. What I mean is when ffi\CData is of a pointer type, then maybe it's alright to dereference it in var_dump() and friends if it's of a known type to help with debugging. But properties-wise, I think it should have the only property like “cdata” but for pointers, named for example “intptr” (also maybe readonly).