Eryk Sun added the comment:

classify_argument is in Modules/_ctypes/libffi/src/x86/ffi64.c. This file is 
for the 64-bit Unix ABI. libffi doesn't use it for 64-bit Windows. 

Some (all?) Linux distros link ctypes to the system libffi. In my experience, 
building 3.6 on Linux defaults to the system libffi, and I don't personally 
know how to override this. Configuring "--without-system-ffi" seems to be 
ignored.

Regarding your Test struct example, it's ok in this particular case to classify 
an 8-byte integer array the same as an 8-byte pointer. It doesn't abort() 
because the 2nd word isn't left unclassified (i.e. X86_64_NO_CLASS). 

    import ctypes

    class Test(ctypes.Structure):
        _fields_ = (('foo', ctypes.c_int),
                    ('bar', ctypes.c_int),
                    ('data', ctypes.c_uint8 * 8))

    @ctypes.CFUNCTYPE(None, Test)
    def func(t):
        print('foo:', t.foo)
        print('bar:', t.bar)
        print('data:', t.data[:])

    t = Test(5, 10, tuple(range(8)))

    >>> hex(id(Test))
    '0x9d8ad8'

The ctypes Structure has 3 elements. The first two are ffi_type_sint32 
(FFI_TYPE_SINT32 == 10), and the third is ffi_type_pointer (FFI_TYPE_POINTER == 
14):

    (gdb) set $dict = (StgDictObject *)(((PyTypeObject *)0x9d8ad8)->tp_dict)
    (gdb) p *$dict->ffi_type_pointer->elements[0]
    $1 = {size = 4, alignment = 4, type = 10, elements = 0x0}
    (gdb) p *$dict->ffi_type_pointer->elements[1]
    $2 = {size = 4, alignment = 4, type = 10, elements = 0x0}
    (gdb) p *$dict->ffi_type_pointer->elements[2]
    $3 = {size = 8, alignment = 8, type = 14, elements = 0x0}
    (gdb) p $dict->ffi_type_pointer->elements[3]
    $4 = (struct _ffi_type *) 0x0

classify_argument() recursively classifies and merges these elements. The first 
two get merged as X86_64_INTEGER_CLASS, and the 'pointer' (actually an array) 
is X86_64_INTEGER_CLASS.

    >>> func(t)

    Breakpoint 1, ffi_call (cif=cif@entry=0x7fffffffd570, 
fn=fn@entry=0x7ffff7fee010,
        rvalue=rvalue@entry=0x7fffffffd630, avalue=avalue@entry=0x7fffffffd610)
        at ../src/x86/ffi64.c:424

    [...snip...]

    458   for (i = 0; i < avn; ++i)
    (gdb) 
    462       n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
    (gdb) 
    463       if (n == 0
    (gdb) p n
    $6 = 2
    (gdb) p ngpr
    $7 = 2
    (gdb) p classes[0]
    $8 = X86_64_INTEGER_CLASS
    (gdb) p classes[1]
    $9 = X86_64_INTEGER_CLASS

The struct is passed in two general-purpose integer registers, rdi and rsi:

    Breakpoint 2, ffi_call_unix64 () at ../src/x86/unix64.S:49
    49          movq    (%rsp), %r10            /* Load return address.  */

    [...snip...]
    76          call    *%r11

    (gdb) p/x $rdi
    $10 = 0xa00000005
    (gdb) p/x $rsi
    $11 = 0x706050403020100
    (gdb) c
    Continuing.

    foo: 5
    bar: 10
    data: [0, 1, 2, 3, 4, 5, 6, 7]

----------

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

Reply via email to