Skip to content

Commit 762dd09

Browse files
committed
Review suggestion for zend_ffi_zval_to_cdata()
1 parent cc062c6 commit 762dd09

File tree

1 file changed

+48
-31
lines changed

1 file changed

+48
-31
lines changed

ext/ffi/ffi.c

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -188,21 +188,6 @@ typedef struct _zend_ffi {
188188
#define ZEND_FFI_SIZEOF_ARG \
189189
MAX(FFI_SIZEOF_ARG, sizeof(double))
190190

191-
/* The FFI call return values follow widening rules.
192-
* We must widen to `ffi_arg` in the case we're handling a return value for types shorter than the machine width.
193-
* From http://www.chiark.greenend.org.uk/doc/libffi-dev/html/The-Closure-API.html:
194-
* > In most cases, ret points to an object of exactly the size of the type specified when cif was constructed.
195-
* > However, integral types narrower than the system register size are widened.
196-
* > In these cases your program may assume that ret points to an ffi_arg object.
197-
*/
198-
#define ZEND_FFI_WRITE_NARROW(ty, ptr, val, is_ret) do { \
199-
if (is_ret) { \
200-
*(ffi_arg *) ptr = (ffi_arg) (ty) val; \
201-
} else { \
202-
*(ty *) ptr = val; \
203-
} \
204-
} while (0)
205-
206191
typedef struct _zend_ffi_cdata {
207192
zend_object std;
208193
zend_ffi_type *type;
@@ -784,20 +769,21 @@ static void zend_ffi_zval_to_bit_field(void *ptr, zend_ffi_field *field, zval *v
784769
}
785770
/* }}} */
786771

787-
static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi_type *type, zval *value, bool is_ret) /* {{{ */
772+
static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi_type *type, zend_ffi_type_kind kind, zval *value, bool is_ret) /* {{{ */
788773
{
789774
zend_long lval;
790775
double dval;
791776
zend_string *tmp_str;
792777
zend_string *str;
793-
zend_ffi_type_kind kind = type->kind;
794778

795779
/* Pointer type has special handling of CData */
796780
if (kind != ZEND_FFI_TYPE_POINTER && Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) {
797781
zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value);
798782
if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type)) &&
799783
type->size == ZEND_FFI_TYPE(cdata->type)->size) {
800784
if (is_ret && type->size < sizeof(ffi_arg)) {
785+
/* Do not widen the reads because that may over-read bytes. */
786+
kind = type->kind;
801787
again_narrowed:
802788
switch (kind) {
803789
case ZEND_FFI_TYPE_SINT8:
@@ -850,27 +836,27 @@ static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi
850836
#endif
851837
case ZEND_FFI_TYPE_UINT8:
852838
lval = zval_get_long(value);
853-
ZEND_FFI_WRITE_NARROW(uint8_t, ptr, lval, is_ret);
839+
*(uint8_t*)ptr = lval;
854840
break;
855841
case ZEND_FFI_TYPE_SINT8:
856842
lval = zval_get_long(value);
857-
ZEND_FFI_WRITE_NARROW(int8_t, ptr, lval, is_ret);
843+
*(int8_t*)ptr = lval;
858844
break;
859845
case ZEND_FFI_TYPE_UINT16:
860846
lval = zval_get_long(value);
861-
ZEND_FFI_WRITE_NARROW(uint16_t, ptr, lval, is_ret);
847+
*(uint16_t*)ptr = lval;
862848
break;
863849
case ZEND_FFI_TYPE_SINT16:
864850
lval = zval_get_long(value);
865-
ZEND_FFI_WRITE_NARROW(int16_t, ptr, lval, is_ret);
851+
*(int16_t*)ptr = lval;
866852
break;
867853
case ZEND_FFI_TYPE_UINT32:
868854
lval = zval_get_long(value);
869-
ZEND_FFI_WRITE_NARROW(uint32_t, ptr, lval, is_ret);
855+
*(uint32_t*)ptr = lval;
870856
break;
871857
case ZEND_FFI_TYPE_SINT32:
872858
lval = zval_get_long(value);
873-
ZEND_FFI_WRITE_NARROW(int32_t, ptr, lval, is_ret);
859+
*(int32_t*)ptr = lval;
874860
break;
875861
case ZEND_FFI_TYPE_UINT64:
876862
lval = zval_get_long(value);
@@ -881,12 +867,12 @@ static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi
881867
*(int64_t*)ptr = lval;
882868
break;
883869
case ZEND_FFI_TYPE_BOOL:
884-
ZEND_FFI_WRITE_NARROW(uint8_t, ptr, zend_is_true(value), is_ret);
870+
*(uint8_t*)ptr = zend_is_true(value);
885871
break;
886872
case ZEND_FFI_TYPE_CHAR:
887873
str = zval_get_tmp_string(value, &tmp_str);
888874
if (ZSTR_LEN(str) == 1) {
889-
ZEND_FFI_WRITE_NARROW(char, ptr, ZSTR_VAL(str)[0], is_ret);
875+
*(uint8_t*)ptr = ZSTR_VAL(str)[0];
890876
} else {
891877
zend_tmp_string_release(tmp_str);
892878
zend_ffi_assign_incompatible(value, type);
@@ -1065,7 +1051,38 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
10651051

10661052
ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type);
10671053
if (ret_type->kind != ZEND_FFI_TYPE_VOID) {
1068-
zend_ffi_zval_to_cdata(ret, ret_type, &retval, true);
1054+
zend_ffi_type_kind kind = ret_type->kind;
1055+
1056+
/* Return values are widened to a machine register. */
1057+
if (kind == ZEND_FFI_TYPE_ENUM) {
1058+
kind = ret_type->enumeration.kind;
1059+
}
1060+
switch (kind) {
1061+
case ZEND_FFI_TYPE_BOOL:
1062+
case ZEND_FFI_TYPE_CHAR:
1063+
case ZEND_FFI_TYPE_UINT8:
1064+
case ZEND_FFI_TYPE_UINT16:
1065+
#if SIZEOF_SIZE_T == 8
1066+
case ZEND_FFI_TYPE_UINT32:
1067+
kind = ZEND_FFI_TYPE_UINT64;
1068+
#else
1069+
kind = ZEND_FFI_TYPE_UINT32;
1070+
#endif
1071+
break;
1072+
case ZEND_FFI_TYPE_SINT8:
1073+
case ZEND_FFI_TYPE_SINT16:
1074+
#if SIZEOF_SIZE_T == 8
1075+
case ZEND_FFI_TYPE_SINT32:
1076+
kind = ZEND_FFI_TYPE_SINT64;
1077+
#else
1078+
kind = ZEND_FFI_TYPE_SINT32;
1079+
#endif
1080+
break;
1081+
default:
1082+
break;
1083+
}
1084+
1085+
zend_ffi_zval_to_cdata(ret, ret_type, kind, &retval, true);
10691086
}
10701087

10711088
zval_ptr_dtor(&retval);
@@ -1219,7 +1236,7 @@ static zval *zend_ffi_cdata_set(zend_object *obj, zend_string *member, zval *val
12191236
return &EG(uninitialized_zval);
12201237
}
12211238

1222-
zend_ffi_zval_to_cdata(cdata->ptr, type, value, false);
1239+
zend_ffi_zval_to_cdata(cdata->ptr, type, type->kind, value, false);
12231240

12241241
return value;
12251242
}
@@ -1441,7 +1458,7 @@ static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_nam
14411458

14421459
if (EXPECTED(!field->bits)) {
14431460
ptr = (void*)(((char*)ptr) + field->offset);
1444-
zend_ffi_zval_to_cdata(ptr, ZEND_FFI_TYPE(field->type), value, false);
1461+
zend_ffi_zval_to_cdata(ptr, ZEND_FFI_TYPE(field->type), ZEND_FFI_TYPE(field->type)->kind, value, false);
14451462
} else {
14461463
zend_ffi_zval_to_bit_field(ptr, field, value);
14471464
}
@@ -1555,7 +1572,7 @@ static void zend_ffi_cdata_write_dim(zend_object *obj, zval *offset, zval *value
15551572
return;
15561573
}
15571574

1558-
zend_ffi_zval_to_cdata(ptr, type, value, false);
1575+
zend_ffi_zval_to_cdata(ptr, type, type->kind, value, false);
15591576
}
15601577
/* }}} */
15611578

@@ -2620,7 +2637,7 @@ static zval *zend_ffi_write_var(zend_object *obj, zend_string *var_name, zval *v
26202637
return value;
26212638
}
26222639

2623-
zend_ffi_zval_to_cdata(sym->addr, ZEND_FFI_TYPE(sym->type), value, false);
2640+
zend_ffi_zval_to_cdata(sym->addr, ZEND_FFI_TYPE(sym->type), ZEND_FFI_TYPE(sym->type)->kind, value, false);
26242641
return value;
26252642
}
26262643
/* }}} */
@@ -4097,7 +4114,7 @@ ZEND_METHOD(FFI, cast) /* {{{ */
40974114
cdata->std.handlers = &zend_ffi_cdata_value_handlers;
40984115
cdata->type = type_ptr;
40994116
cdata->ptr = emalloc(type->size);
4100-
zend_ffi_zval_to_cdata(cdata->ptr, type, zv, false);
4117+
zend_ffi_zval_to_cdata(cdata->ptr, type, type->kind, zv, false);
41014118
cdata->flags = ZEND_FFI_FLAG_OWNED;
41024119
if (is_const) {
41034120
cdata->flags |= ZEND_FFI_FLAG_CONST;

0 commit comments

Comments
 (0)