This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
Floating-point variadic function call
- From: Damien Thébault <damien at dtbo dot net>
- To: libffi-discuss at sourceware dot org
- Date: Mon, 10 Oct 2016 09:03:52 +0200
- Subject: Floating-point variadic function call
- Authentication-results: sourceware.org; auth=none
Hello,
I am trying to use libffi to call various functions, and my first try
was with printf(). As this is a variadic function, I used
ffi_prep_cif_var(). Everything seems to be working, except with floats,
which are not working, and are even generating wrong memory accesses
(detected by valgrind).
A similar function with ffi_prep_cif() and floats is working properly.
Could type promotion from float to double be the issue here ?
Does libffi handle type promotion in variadic calls or is it the
caller's job ?
I tested on a x86_64 computer both 64-bit and 32-bit versions (the
latter compiled with -m32) as well as ARM under qemu.
In all those cases, I didn't get the proper result with floats while
doubles are ok, as well as chars.
I've attached a sample source file that reproduces the problem and here
is the output of one test run:
$ gcc $(pkg-config --cflags --libs libffi) -std=c99 -pedantic -Wall -Wextra libffi_variadic_printf.c -o libffi_variadic_printf
$ ./libffi_variadic_printf
Non-variadic call:
[1.100000,2.200000,3.300000,4.400000,5.500000,6.600000,7.700000,8.800000,9.900000]
result is 83
Variadic call:
[0.000000,0.000000,0.000000,0.000000,0.000000,91750.390826,0.000000,0.000000,0.000000]
result is 87
Thanks,
#include <stdio.h>
#include <ffi.h>
int print9float(const char *fmt,
float f1, float f2, float f3, float f4, float f5,
float f6, float f7, float f8, float f9)
{
return printf(fmt, f1, f2, f3, f4, f5, f6, f7, f8, f9);
}
void test_float()
{
size_t i;
ffi_cif cif;
ffi_type *arg_types[10];
void *arg_values[10];
char *fmt = "[%f,%f,%f,%f,%f,%f,%f,%f,%f]\n";
float floatargs[9] = {1.1f,2.2f,3.3f,4.4f,5.5f,6.6f,7.7f,8.8f,9.9f};
ffi_status status;
int result;
arg_types[0] = &ffi_type_pointer;
for(i=1 ; i<10 ; i++)
{
arg_types[i] = &ffi_type_float;
}
if((status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, 10,
&ffi_type_sint, arg_types)) != FFI_OK)
{
fprintf(stderr, "ffi_prep_cif_var() failed!\n");
return;
}
arg_values[0] = &fmt;
for(i=1 ; i<10 ; i++)
{
arg_values[i] = &floatargs[i-1];
}
printf("Non-variadic call:\n");
ffi_call(&cif, FFI_FN(print9float), &result, arg_values);
printf("result is %i\n", result);
}
void test_varfloat()
{
size_t i;
ffi_cif cif;
ffi_type *arg_types[10];
void *arg_values[10];
char *fmt = "[%f,%f,%f,%f,%f,%f,%f,%f,%f]\n";
float floatargs[9] = {1.1f,2.2f,3.3f,4.4f,5.5f,6.6f,7.7f,8.8f,9.9f};
ffi_status status;
int result;
arg_types[0] = &ffi_type_pointer;
for(i=1 ; i<10 ; i++)
{
arg_types[i] = &ffi_type_float;
}
if((status = ffi_prep_cif_var(&cif, FFI_DEFAULT_ABI, 1, 10,
&ffi_type_sint, arg_types)) != FFI_OK)
{
fprintf(stderr, "ffi_prep_cif_var() failed!\n");
return;
}
arg_values[0] = &fmt;
for(i=1 ; i<10 ; i++)
{
arg_values[i] = &floatargs[i-1];
}
printf("Variadic call:\n");
ffi_call(&cif, FFI_FN(printf), &result, arg_values);
printf("result is %i\n", result);
}
int main()
{
test_float();
test_varfloat();
return 0;
}