@@ -188,21 +188,6 @@ typedef struct _zend_ffi {
188
188
#define ZEND_FFI_SIZEOF_ARG \
189
189
MAX(FFI_SIZEOF_ARG, sizeof(double))
190
190
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
-
206
191
typedef struct _zend_ffi_cdata {
207
192
zend_object std ;
208
193
zend_ffi_type * type ;
@@ -784,20 +769,21 @@ static void zend_ffi_zval_to_bit_field(void *ptr, zend_ffi_field *field, zval *v
784
769
}
785
770
/* }}} */
786
771
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 ) /* {{{ */
788
773
{
789
774
zend_long lval ;
790
775
double dval ;
791
776
zend_string * tmp_str ;
792
777
zend_string * str ;
793
- zend_ffi_type_kind kind = type -> kind ;
794
778
795
779
/* Pointer type has special handling of CData */
796
780
if (kind != ZEND_FFI_TYPE_POINTER && Z_TYPE_P (value ) == IS_OBJECT && Z_OBJCE_P (value ) == zend_ffi_cdata_ce ) {
797
781
zend_ffi_cdata * cdata = (zend_ffi_cdata * )Z_OBJ_P (value );
798
782
if (zend_ffi_is_compatible_type (type , ZEND_FFI_TYPE (cdata -> type )) &&
799
783
type -> size == ZEND_FFI_TYPE (cdata -> type )-> size ) {
800
784
if (is_ret && type -> size < sizeof (ffi_arg )) {
785
+ /* Do not widen the reads because that may over-read bytes. */
786
+ kind = type -> kind ;
801
787
again_narrowed :
802
788
switch (kind ) {
803
789
case ZEND_FFI_TYPE_SINT8 :
@@ -850,27 +836,27 @@ static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi
850
836
#endif
851
837
case ZEND_FFI_TYPE_UINT8 :
852
838
lval = zval_get_long (value );
853
- ZEND_FFI_WRITE_NARROW (uint8_t , ptr , lval , is_ret ) ;
839
+ * (uint8_t * ) ptr = lval ;
854
840
break ;
855
841
case ZEND_FFI_TYPE_SINT8 :
856
842
lval = zval_get_long (value );
857
- ZEND_FFI_WRITE_NARROW (int8_t , ptr , lval , is_ret ) ;
843
+ * (int8_t * ) ptr = lval ;
858
844
break ;
859
845
case ZEND_FFI_TYPE_UINT16 :
860
846
lval = zval_get_long (value );
861
- ZEND_FFI_WRITE_NARROW (uint16_t , ptr , lval , is_ret ) ;
847
+ * (uint16_t * ) ptr = lval ;
862
848
break ;
863
849
case ZEND_FFI_TYPE_SINT16 :
864
850
lval = zval_get_long (value );
865
- ZEND_FFI_WRITE_NARROW (int16_t , ptr , lval , is_ret ) ;
851
+ * (int16_t * ) ptr = lval ;
866
852
break ;
867
853
case ZEND_FFI_TYPE_UINT32 :
868
854
lval = zval_get_long (value );
869
- ZEND_FFI_WRITE_NARROW (uint32_t , ptr , lval , is_ret ) ;
855
+ * (uint32_t * ) ptr = lval ;
870
856
break ;
871
857
case ZEND_FFI_TYPE_SINT32 :
872
858
lval = zval_get_long (value );
873
- ZEND_FFI_WRITE_NARROW (int32_t , ptr , lval , is_ret ) ;
859
+ * (int32_t * ) ptr = lval ;
874
860
break ;
875
861
case ZEND_FFI_TYPE_UINT64 :
876
862
lval = zval_get_long (value );
@@ -881,12 +867,12 @@ static zend_always_inline zend_result zend_ffi_zval_to_cdata(void *ptr, zend_ffi
881
867
* (int64_t * )ptr = lval ;
882
868
break ;
883
869
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 );
885
871
break ;
886
872
case ZEND_FFI_TYPE_CHAR :
887
873
str = zval_get_tmp_string (value , & tmp_str );
888
874
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 ];
890
876
} else {
891
877
zend_tmp_string_release (tmp_str );
892
878
zend_ffi_assign_incompatible (value , type );
@@ -1065,7 +1051,38 @@ static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, v
1065
1051
1066
1052
ret_type = ZEND_FFI_TYPE (callback_data -> type -> func .ret_type );
1067
1053
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);
1069
1086
}
1070
1087
1071
1088
zval_ptr_dtor (& retval );
@@ -1219,7 +1236,7 @@ static zval *zend_ffi_cdata_set(zend_object *obj, zend_string *member, zval *val
1219
1236
return & EG (uninitialized_zval );
1220
1237
}
1221
1238
1222
- zend_ffi_zval_to_cdata (cdata -> ptr , type , value , false);
1239
+ zend_ffi_zval_to_cdata (cdata -> ptr , type , type -> kind , value , false);
1223
1240
1224
1241
return value ;
1225
1242
}
@@ -1441,7 +1458,7 @@ static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_nam
1441
1458
1442
1459
if (EXPECTED (!field -> bits )) {
1443
1460
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);
1445
1462
} else {
1446
1463
zend_ffi_zval_to_bit_field (ptr , field , value );
1447
1464
}
@@ -1555,7 +1572,7 @@ static void zend_ffi_cdata_write_dim(zend_object *obj, zval *offset, zval *value
1555
1572
return ;
1556
1573
}
1557
1574
1558
- zend_ffi_zval_to_cdata (ptr , type , value , false);
1575
+ zend_ffi_zval_to_cdata (ptr , type , type -> kind , value , false);
1559
1576
}
1560
1577
/* }}} */
1561
1578
@@ -2620,7 +2637,7 @@ static zval *zend_ffi_write_var(zend_object *obj, zend_string *var_name, zval *v
2620
2637
return value ;
2621
2638
}
2622
2639
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);
2624
2641
return value ;
2625
2642
}
2626
2643
/* }}} */
@@ -4097,7 +4114,7 @@ ZEND_METHOD(FFI, cast) /* {{{ */
4097
4114
cdata -> std .handlers = & zend_ffi_cdata_value_handlers ;
4098
4115
cdata -> type = type_ptr ;
4099
4116
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);
4101
4118
cdata -> flags = ZEND_FFI_FLAG_OWNED ;
4102
4119
if (is_const ) {
4103
4120
cdata -> flags |= ZEND_FFI_FLAG_CONST ;
0 commit comments