Incorrect data detected in the nested float struct with x86/libffi on Linux/64bit

Cheng Jin jincheng@ca.ibm.com
Thu Jun 10 02:39:00 GMT 2021




Hi Kaz,

It is highly likely that the version of libffi coming with Ubuntu 18 is
outdated (we experienced the same abort with an outdated x86/libffi
integrated in our own project).
Please try the latest version of x86/libffi at
https://github.com/libffi/libffi/tree/master/src/x86.

In addition, adding padding to the nested structure might work but doesn't
make any sense as ffi_prep_cif() will detect/compute the padding
automatically in the code, in which case everything related to padding
should be handled by libffi rather than by users. That's why they need to
investigate why it failed to handle on Linux/64bit given it works good on
other platforms (e.g. Windows/x86_64, Aarch64).


Thanks and Best Regards
Cheng Jin




From:	"Kaz Kylheku (libffi)" <382-725-6798@kylheku.com>
To:	Cheng Jin <jincheng@ca.ibm.com>
Cc:	libffi-discuss@sourceware.org
Date:	2021-06-09 10:05 PM
Subject:	[EXTERNAL] Re: Incorrect data detected in the nested float
            struct with  x86/libffi on Linux/64bit



On 2021-06-09 09:41, Cheng Jin via Libffi-discuss wrote:
> Hi,
>
> We found that the nested struct [[float, float], float] works good with
> x86/libffi (at
https://github.com/libffi/libffi/tree/master/src/x86
 )
> on Linux/64bit (verified on Ubuntu 19) while a variant of it like
> [float,[float,float]] was messed up at the 3rd element when invoking
> ffi_call() in the following test:

In the libffi that comes with Ubuntu 18.04 Server, x84-64, your test
case aborts in ffi_call.

I built a similar test case in which I put your function into a shared
lib, and used a libffi-based programming language to call it. Same
thing: abort in ffi_call.

There is some problem in that version of libffi; it doesn't like small
structures. If I add padding to the structure, then there is no abort.

My version of the function looks like this:

float_t testNestedFloatStruct(float_t arg1, stru_Nested_F arg2)
{
   float_t floatSum = arg1 + arg2.elem1 + arg2.elem2.elem1 +
arg2.elem2.elem2;
   puts("called");
   printf("arg1 = %f, arg2 = { %f, { %f, %f } }\n", arg1, arg2.elem1,
          arg2.elem2.elem1, arg2.elem2.elem2);
   return floatSum;
}

On the FFI side, if I add a uint64's worth of padding to the structure,
the ffi_call proceeds without abort, and the result is like this:

arg1 = 1.000000, arg2 = { 0.000000, { 0.000000,
-52784298695107543040.000000 } }
-5.27842986951075e19

The second line is the caller printing the return value. As you can
see, complete rubbish.

If I take out the padding and change everything to double (my float_f
typedef lets me do that easily), it looks like this:

arg1 = 1.000000, arg2 = { 2.000000, { 3.000000, 4.000000 } }
10.0

That's the expected behavior; the all-float case should look the same.

Basically with the padding, although the call works, it's using the
wrong
calling conventions. I think this small structure is supposed to be
passed
in registers.

If I step over the ffi_prep_cif call to see what args were passed to it
and how the sizes and alignment were set, all looks good:

ffi_make_call_desc (ntotal=<optimized out>, nfixed=<optimized out>,
     rettype=0x7ffff7f97780, argtypes=<optimized out>, name_in=<optimized
out>)
     at ffi.c:4831
4831      if (ffis != FFI_OK)
(gdb) p args[0]
$5 = (ffi_type *) 0x758c80 <ffi_type_float>
(gdb) p args[1]
$6 = (ffi_type *) 0xc38220
(gdb) p (*args[1])
$7 = {size = 12, alignment = 4, type = 13, elements = 0xc38240}
(gdb) p (*args[1]).elements[0]
$8 = (struct _ffi_type *) 0x758c80 <ffi_type_float>
(gdb) p (*args[1]).elements[1]
$9 = (struct _ffi_type *) 0xb92160
(gdb) p (*(*args[1]).elements[1])
$10 = {size = 8, alignment = 4, type = 13, elements = 0xb92180}
(gdb) p (*(*args[1]).elements[1]).elements[0]
$11 = (struct _ffi_type *) 0x758c80 <ffi_type_float>
(gdb) p (*(*args[1]).elements[1]).elements[1]
$12 = (struct _ffi_type *) 0x758c80 <ffi_type_float>
(gdb) p (*(*args[1]).elements[1]).elements[2]
$13 = (struct _ffi_type *) 0x0
(gdb) p (*args[1]).elements[2]
$14 = (struct _ffi_type *) 0x0


Both elements arrays have two elements and a null terminator. Two floats
at the leaves, and a float + struct at the first level.



-------------- next part --------------
A non-text attachment was scrubbed...
Name: graycol.gif
Type: image/gif
Size: 105 bytes
Desc: not available
URL: <https://sourceware.org/pipermail/libffi-discuss/attachments/20210609/1f362cfe/attachment.gif>


More information about the Libffi-discuss mailing list