unix/modffi: Fix conversion between Python integers and ffi types.

This commit fixes the following problems converting to/from Python integers
and ffi types:
- integers of 8 and 16 bits not working on big endian
- integers of 64 bits not working on 32 bits architectures
- unsigned returns were converted to signed Python integers

Fixes issue #7269.
This commit is contained in:
Abilio Marques 2021-05-16 05:30:25 +02:00 committed by Damien George
parent 20a8f4f7ec
commit 525a920ca5
1 changed files with 63 additions and 1 deletions

View File

@ -35,6 +35,7 @@
#include "py/runtime.h"
#include "py/binary.h"
#include "py/mperrno.h"
#include "py/objint.h"
/*
* modffi uses character codes to encode a value type, based on "struct"
@ -59,6 +60,11 @@
// This union is large enough to hold any supported argument/return value.
typedef union _ffi_union_t {
ffi_arg ffi;
unsigned char B;
unsigned short int H;
unsigned int I;
unsigned long int L;
unsigned long long int Q;
float flt;
double dbl;
} ffi_union_t;
@ -177,6 +183,20 @@ STATIC mp_obj_t return_ffi_value(ffi_union_t *val, char type) {
return mp_obj_new_float_from_d(val->dbl);
}
#endif
case 'b':
case 'h':
case 'i':
case 'l':
return mp_obj_new_int((signed)val->ffi);
case 'B':
case 'H':
case 'I':
case 'L':
return mp_obj_new_int_from_uint(val->ffi);
case 'q':
return mp_obj_new_int_from_ll(val->Q);
case 'Q':
return mp_obj_new_int_from_ull(val->Q);
case 'O':
return (mp_obj_t)(intptr_t)val->ffi;
default:
@ -365,6 +385,48 @@ STATIC void ffifunc_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
mp_printf(print, "<ffifunc %p>", self->func);
}
STATIC unsigned long long ffi_get_int_value(mp_obj_t o) {
if (mp_obj_is_small_int(o)) {
return MP_OBJ_SMALL_INT_VALUE(o);
} else {
unsigned long long res;
mp_obj_int_to_bytes_impl(o, MP_ENDIANNESS_BIG, sizeof(res), (byte *)&res);
return res;
}
}
STATIC ffi_union_t ffi_int_obj_to_ffi_union(mp_obj_t o, const char argtype) {
ffi_union_t ret;
if ((argtype | 0x20) == 'q') {
ret.Q = ffi_get_int_value(o);
return ret;
} else {
mp_uint_t val = mp_obj_int_get_truncated(o);
switch (argtype) {
case 'b':
case 'B':
ret.B = val;
break;
case 'h':
case 'H':
ret.H = val;
break;
case 'i':
case 'I':
ret.I = val;
break;
case 'l':
case 'L':
ret.L = val;
break;
default:
ret.ffi = val;
break;
}
}
return ret;
}
STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
(void)n_kw;
mp_obj_ffifunc_t *self = MP_OBJ_TO_PTR(self_in);
@ -387,7 +449,7 @@ STATIC mp_obj_t ffifunc_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const
} else if (a == mp_const_none) {
values[i].ffi = 0;
} else if (mp_obj_is_int(a)) {
values[i].ffi = mp_obj_int_get_truncated(a);
values[i] = ffi_int_obj_to_ffi_union(a, *argtype);
} else if (mp_obj_is_str(a)) {
const char *s = mp_obj_str_get_str(a);
values[i].ffi = (ffi_arg)(intptr_t)s;