Author eryksun
Recipients amaury.forgeotdarc, belopolsky, eryksun, meador.inge, tilsche
Date 2016-03-25.03:04:38
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1458875080.64.0.29309877588.issue26628@psf.upfronthosting.co.za>
In-reply-to
Content
> 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.
History
Date User Action Args
2016-03-25 03:04:40eryksunsetrecipients: + eryksun, amaury.forgeotdarc, belopolsky, meador.inge, tilsche
2016-03-25 03:04:40eryksunsetmessageid: <1458875080.64.0.29309877588.issue26628@psf.upfronthosting.co.za>
2016-03-25 03:04:40eryksunlinkissue26628 messages
2016-03-25 03:04:38eryksuncreate