-
Notifications
You must be signed in to change notification settings - Fork 7.9k
FFI add get value of the pointer variable #14609
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
base: master
Are you sure you want to change the base?
Conversation
sync master
sync master
sync master
sync master
sync master
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't like the introduction of the new FFI::addrValue()
method.
Instead, I would propose to use a special "cdata" property for ZEND_FFI_TYPE_POINTER
similar to scalar FFI values.
So you will able to achieve the desired behavior with the following code.
$x = FFI::cdef()->cast("void*", 20);
$v = $x->cdata;
var_dump($v);// output 20
This looks more consistent.
Can you try to implement this?
Unfortunately this is not simple. I tried to implement this myself. diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index 8d9ddaca053..e6066b0aaca 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -1107,6 +1107,17 @@ static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name
field = *(cache_slot + 1);
} else {
if (type->kind == ZEND_FFI_TYPE_POINTER) {
+ if (zend_string_equals_literal(field_name, "cdata")) {
+ if (ptr == &cdata->ptr_holder) {
+ ptr = *(void**)ptr;
+ }
+ if (ptr == NULL) {
+ ZVAL_NULL(rv);
+ } else {
+ ZVAL_LONG(rv, (intptr_t)ptr);
+ }
+ return rv;
+ }
type = ZEND_FFI_TYPE(type->pointer.type);
}
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
@@ -1184,6 +1195,16 @@ static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_nam
return value;
}
if (type->kind == ZEND_FFI_TYPE_POINTER) {
+ if (zend_string_equals_literal(field_name, "cdata")) {
+ if (Z_TYPE_P(value) == IS_NULL) {
+ *(void**)ptr = NULL;
+ } else if (Z_TYPE_P(value) == IS_LONG) {
+ *(void**)ptr = (void*)(intptr_t)Z_LVAL_P(value);
+ } else {
+ zend_ffi_zval_to_cdata(ptr, type, value);
+ }
+ return value;
+ }
type = ZEND_FFI_TYPE(type->pointer.type);
}
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { But this breaks The pointer support in ext/FFI is really messy :( |
It's possible to support "cdata" only for "hold" pointers (the original PR also supported only "hold" pointers). The following patch works, but it's hard to explain when "cdata" is used for pointer and when for the referenced data. diff --git a/ext/ffi/ffi.c b/ext/ffi/ffi.c
index 8d9ddaca053..ac9952b7519 100644
--- a/ext/ffi/ffi.c
+++ b/ext/ffi/ffi.c
@@ -1107,6 +1107,15 @@ static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name
field = *(cache_slot + 1);
} else {
if (type->kind == ZEND_FFI_TYPE_POINTER) {
+ if (ptr == &cdata->ptr_holder && zend_string_equals_literal(field_name, "cdata")) {
+ ptr = *(void**)ptr;
+ if (ptr == NULL) {
+ ZVAL_NULL(rv);
+ } else {
+ ZVAL_LONG(rv, (intptr_t)ptr);
+ }
+ return rv;
+ }
type = ZEND_FFI_TYPE(type->pointer.type);
}
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
@@ -1184,6 +1193,16 @@ static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_nam
return value;
}
if (type->kind == ZEND_FFI_TYPE_POINTER) {
+ if (ptr == &cdata->ptr_holder && zend_string_equals_literal(field_name, "cdata")) {
+ if (Z_TYPE_P(value) == IS_NULL) {
+ *(void**)ptr = NULL;
+ } else if (Z_TYPE_P(value) == IS_LONG) {
+ *(void**)ptr = (void*)(intptr_t)Z_LVAL_P(value);
+ } else {
+ zend_ffi_zval_to_cdata(ptr, type, value);
+ }
+ return value;
+ }
type = ZEND_FFI_TYPE(type->pointer.type);
}
if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) { @nielsdos @arnaud-lb @iluuu1994 @bwoebi any thoughts? |
I think that casting to $x = FFI::cdef()->cast("char*", 20);
$v = FFI::cdef()->cast("uintptr_t", $x)->cdata;
var_dump($v); // int(20) This works currently, except for Lines 4055 to 4059 in 5a3c4a2
A workaround is to cast $x = FFI::cdef()->cast("void*", 20);
$x = FFI::cdef()->cast("char*", $x);
$v = FFI::cdef()->cast("uintptr_t", $x)->cdata;
var_dump($v); // int(20) However casting to I like what you suggested in #14609 (review), but as property accesses on If a method on $x = FFI::cdef()->cast("int", 20);
FFI::value($x); // int(20)
$x = FFI::cdef()->cast("void*", 20);
FFI::value($x); // int(20) |
|
Get value of the pointer variable, smailer:
in php