Eryk Sun added the comment:

> I would strongly argue to generally prohibit this 
> with an exception

I agree. A warning in the tutorial isn't sufficient. ctypes should raise an 
error when setting a union or bitfield struct type in argtypes or when passing 
one by value.

Here's some background to flesh out this issue. Both struct and union types are 
defined as the libffi type FFI_TYPE_STRUCT (13), since FFI_TYPE_UNION doesn't 
exist. 

    class MyUnion(ctypes.Union):
        _fields_ = [("x%s" % i, ctypes.c_double) for i in range(11)]

    >>> stgdict(MyUnion).length
    11
    >>> stgdict(MyUnion).ffi_type_pointer
    size: 8
    alignment: 8
    type: 13
    elements: 17918992

    >>> (ctypes.c_void_p * 12).from_address(17918992)[:]
    [140354450953784, 140354450953784, 140354450953784, 140354450953784,
     140354450953784, 140354450953784, 140354450953784, 140354450953784,
     140354450953784, 140354450953784, 140354450953784, None]

    >>> ffi_type.from_address(140354450953784)
    size: 8
    alignment: 8
    type: 3
    elements: LP_LP_ffi_type(<NULL>)

Type 3 is FFI_TYPE_DOUBLE.

    class MyStruct(ctypes.Structure):
        _fields_ = [("x%s" % i, ctypes.c_double) for i in range(11)]

    >>> stgdict(MyStruct).length
    11
    >>> stgdict(MyStruct).ffi_type_pointer
    size: 88
    alignment: 8
    type: 13
    elements: 17868096
    >>> (ctypes.c_void_p * 12).from_address(17868096)[:]
    [140354450953784, 140354450953784, 140354450953784, 140354450953784,
     140354450953784, 140354450953784, 140354450953784, 140354450953784,
     140354450953784, 140354450953784, 140354450953784, None]

As shown above, FFI_TYPE_STRUCT uses the `elements` array in its ffi_type. Each 
element is a pointer to an ffi_type for the corresponding field in the struct 
or union. This array is terminated by a NULL pointer. 

The C data size of a MyUnion instance is 8 bytes. This is less than 32 bytes 
(i.e. four 8-byte words), so the code in classify_argument rightfully assumes 
the argument won't be passed on the stack. Thus it classifies the register 
type(s) to use, presuming it's dealing with a struct. But since it's a union 
the total size of the elements is unrelated to the union's size. libffi would 
need to implement an FFI_TYPE_UNION type to support this as a separate case. 
Otherwise ctypes needs to actively forbid passing a union by value.

----------
nosy: +eryksun
versions: +Python 3.6

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue26628>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to