Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix :mod:`ctypes` callbacks returning an integer narrower than a machine
register: the result is now widened to fill the register, as libffi's
closure contract requires.
59 changes: 51 additions & 8 deletions Modules/_ctypes/callbacks.c
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,22 @@
}
#endif

static int
is_narrow_int_ffi_type(int type)
{
switch (type) {
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT32:
return 1;
default:
return 0;
}
}

/******************************************************************************
*
* Call the python object with all arguments
Expand Down Expand Up @@ -222,13 +238,14 @@
if (restype != &ffi_type_void && result) {
assert(setfunc);

#ifdef WORDS_BIGENDIAN
/* See the corresponding code in _ctypes_callproc():
in callproc.c, around line 1219. */
if (restype->type != FFI_TYPE_FLOAT && restype->size < sizeof(ffi_arg)) {
mem = (char *)mem + sizeof(ffi_arg) - restype->size;
}
#endif
/* libffi's closure contract requires integral results narrower
than ffi_arg to fill a whole register, sign-extended if signed;
setfunc() only writes restype->size bytes. Cf. _ctypes_callproc()
in callproc.c. */
ffi_arg widened = 0;
int narrow = restype->size < sizeof(ffi_arg) &&
is_narrow_int_ffi_type(restype->type);
void *resmem = narrow ? &widened : mem;

/* keep is an object we have to keep alive so that the result
stays valid. If there is no such object, the setfunc will
Expand All @@ -239,7 +256,33 @@
be the result. EXCEPT when restype is py_object - Python
itself knows how to manage the refcount of these objects.
*/
PyObject *keep = setfunc(mem, result, restype->size);
PyObject *keep = setfunc(resmem, result, restype->size);

if (narrow && keep != NULL) {
switch (restype->type) {
case FFI_TYPE_SINT8:
widened = (ffi_arg)(ffi_sarg)*(int8_t *)&widened;
break;
case FFI_TYPE_SINT16:
widened = (ffi_arg)(ffi_sarg)*(int16_t *)&widened;

Check warning on line 267 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Address sanitizer (ubuntu-26.04)

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 267 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 267 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 267 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Ubuntu (installed) / build, install and test

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
break;
case FFI_TYPE_SINT32:
widened = (ffi_arg)(ffi_sarg)*(int32_t *)&widened;

Check warning on line 270 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Address sanitizer (ubuntu-26.04)

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 270 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 270 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 270 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Ubuntu (installed) / build, install and test

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
break;
case FFI_TYPE_UINT8:
widened = *(uint8_t *)&widened;
break;
case FFI_TYPE_UINT16:
widened = *(uint16_t *)&widened;

Check warning on line 276 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Address sanitizer (ubuntu-26.04)

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 276 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 276 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 276 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Ubuntu (installed) / build, install and test

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
break;
case FFI_TYPE_UINT32:
widened = *(uint32_t *)&widened;

Check warning on line 279 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Address sanitizer (ubuntu-26.04)

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 279 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 279 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Cross build Linux

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

Check warning on line 279 in Modules/_ctypes/callbacks.c

View workflow job for this annotation

GitHub Actions / Ubuntu (installed) / build, install and test

dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
break;
default:
break;
}
memcpy(mem, &widened, sizeof(ffi_arg));
}

if (keep == NULL) {
/* Could not convert callback result. */
Expand Down
Loading