This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eryksun
Recipients Ilya.Kulakov, alexei.romanov, amaury.forgeotdarc, belopolsky, eryksun, meador.inge, vinay.sajip, weeble
Date 2017-02-20.20:48:20
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1487623701.81.0.478183543078.issue22273@psf.upfronthosting.co.za>
In-reply-to
Content
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]
History
Date User Action Args
2017-02-20 20:48:21eryksunsetrecipients: + eryksun, vinay.sajip, amaury.forgeotdarc, belopolsky, weeble, meador.inge, Ilya.Kulakov, alexei.romanov
2017-02-20 20:48:21eryksunsetmessageid: <1487623701.81.0.478183543078.issue22273@psf.upfronthosting.co.za>
2017-02-20 20:48:21eryksunlinkissue22273 messages
2017-02-20 20:48:20eryksuncreate