@@ -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-
206191typedef 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 ;
801787again_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