@@ -101,6 +101,22 @@ TryAddRef(PyObject *cnv, CDataObject *obj)
101101}
102102#endif
103103
104+ static int
105+ is_narrow_int_ffi_type (int type )
106+ {
107+ switch (type ) {
108+ case FFI_TYPE_SINT8 :
109+ case FFI_TYPE_UINT8 :
110+ case FFI_TYPE_SINT16 :
111+ case FFI_TYPE_UINT16 :
112+ case FFI_TYPE_SINT32 :
113+ case FFI_TYPE_UINT32 :
114+ return 1 ;
115+ default :
116+ return 0 ;
117+ }
118+ }
119+
104120/******************************************************************************
105121 *
106122 * Call the python object with all arguments
@@ -222,13 +238,21 @@ static void _CallPythonObject(ctypes_state *st,
222238 if (restype != & ffi_type_void && result ) {
223239 assert (setfunc );
224240
225- #ifdef WORDS_BIGENDIAN
226- /* See the corresponding code in _ctypes_callproc():
227- in callproc.c, around line 1219. */
228- if (restype -> type != FFI_TYPE_FLOAT && restype -> size < sizeof (ffi_arg )) {
229- mem = (char * )mem + sizeof (ffi_arg ) - restype -> size ;
230- }
231- #endif
241+ /* libffi's closure contract requires integral results narrower
242+ than ffi_arg to fill a whole register, sign-extended if signed;
243+ setfunc() only writes restype->size bytes. */
244+ union {
245+ ffi_arg arg ;
246+ int8_t s8 ;
247+ uint8_t u8 ;
248+ int16_t s16 ;
249+ uint16_t u16 ;
250+ int32_t s32 ;
251+ uint32_t u32 ;
252+ } narrow_res = {0 };
253+ int narrow = restype -> size < sizeof (ffi_arg ) &&
254+ is_narrow_int_ffi_type (restype -> type );
255+ void * resmem = narrow ? (void * )& narrow_res : mem ;
232256
233257 /* keep is an object we have to keep alive so that the result
234258 stays valid. If there is no such object, the setfunc will
@@ -239,7 +263,34 @@ static void _CallPythonObject(ctypes_state *st,
239263 be the result. EXCEPT when restype is py_object - Python
240264 itself knows how to manage the refcount of these objects.
241265 */
242- PyObject * keep = setfunc (mem , result , restype -> size );
266+ PyObject * keep = setfunc (resmem , result , restype -> size );
267+
268+ if (narrow && keep != NULL ) {
269+ ffi_arg widened ;
270+ switch (restype -> type ) {
271+ case FFI_TYPE_SINT8 :
272+ widened = (ffi_arg )(ffi_sarg )narrow_res .s8 ;
273+ break ;
274+ case FFI_TYPE_SINT16 :
275+ widened = (ffi_arg )(ffi_sarg )narrow_res .s16 ;
276+ break ;
277+ case FFI_TYPE_SINT32 :
278+ widened = (ffi_arg )(ffi_sarg )narrow_res .s32 ;
279+ break ;
280+ case FFI_TYPE_UINT8 :
281+ widened = narrow_res .u8 ;
282+ break ;
283+ case FFI_TYPE_UINT16 :
284+ widened = narrow_res .u16 ;
285+ break ;
286+ case FFI_TYPE_UINT32 :
287+ widened = narrow_res .u32 ;
288+ break ;
289+ default :
290+ Py_UNREACHABLE ();
291+ }
292+ memcpy (mem , & widened , sizeof (ffi_arg ));
293+ }
243294
244295 if (keep == NULL ) {
245296 /* Could not convert callback result. */
0 commit comments