Package: libffi-dev Version: 3.0.9-2 Severity: important The test C-code is attached: gcc-4.4 -lffi -lunistring -o test test.c
It can be compiled without libunistring as well (see notes, please): 1. comment out rows #7 and #8 2. uncomment #9 3. gcc-4.4 -lffi -o test test.c What the code does: 1. creates a new ffi_type to emulate size_t; 2. allocates array of types of function arguments: (char *) and (size_t); 3. prepare CIF to call the size_t function with two arguments; 4. allocates array of pointers to two arguments: char *b and size_t a; 5. runs ffi_call and segfaults; The function can be called directly without ffi_call: comment #68 and uncomment the next statement. In this case the code will not cause segfault. I use valgrind to see internals: valgrind --track-origins=yes -q ./test In the case with ffi_call, valgrind shows: --------------------vvvvvvvvvvvvvvvvvvvvvv just before... ==4153== Conditional jump or move depends on uninitialised value(s) ==4153== at 0x4084827: u8_mbtoucr (in /usr/lib/libunistring.so.0.1.2) ==4153== by 0x40842E8: u8_mbsnlen (in /usr/lib/libunistring.so.0.1.2) ==4153== by 0x404154E: ffi_call_SYSV (in /usr/lib/libffi.so.5.0.10) ==4153== by 0x404138D: ffi_call (in /usr/lib/libffi.so.5.0.10) ==4153== by 0x804890C: main (in /home/ygrex/devel/dlffi/test) ==4153== Uninitialised value was created by a heap allocation ==4153== at 0x4023F50: malloc (vg_replace_malloc.c:236) ==4153== by 0x8048852: main (in /home/ygrex/devel/dlffi/test) ==4153== ==4153== Invalid read of size 1 ==4153== at 0x4084822: u8_mbtoucr (in /usr/lib/libunistring.so.0.1.2) ==4153== by 0x40842E8: u8_mbsnlen (in /usr/lib/libunistring.so.0.1.2) ==4153== by 0x404154E: ffi_call_SYSV (in /usr/lib/libffi.so.5.0.10) ==4153== by 0x404138D: ffi_call (in /usr/lib/libffi.so.5.0.10) ==4153== by 0x804890C: main (in /home/ygrex/devel/dlffi/test) ==4153== Address 0x429a0ec is 0 bytes after a block of size 4 alloc'd ==4153== at 0x4023F50: malloc (vg_replace_malloc.c:236) ==4153== by 0x8048852: main (in /home/ygrex/devel/dlffi/test) ==4153== ==4153== ==4153== Process terminating with default action of signal 11 (SIGSEGV) ==4153== Access not within mapped region at address 0x469A000 ==4153== at 0x4084822: u8_mbtoucr (in /usr/lib/libunistring.so.0.1.2) ==4153== by 0x40842E8: u8_mbsnlen (in /usr/lib/libunistring.so.0.1.2) ==4153== by 0x404154E: ffi_call_SYSV (in /usr/lib/libffi.so.5.0.10) ==4153== by 0x404138D: ffi_call (in /usr/lib/libffi.so.5.0.10) ==4153== by 0x804890C: main (in /home/ygrex/devel/dlffi/test) ==4153== If you believe this happened as a result of a stack ==4153== overflow in your program's main thread (unlikely but ==4153== possible), you can try to increase the size of the ==4153== main thread stack using the --main-stacksize= flag. ==4153== The main thread stack size used in this run was 8388608. Segmentation fault --------------------^^^^^^^^^^^^^^^^^^^^^^ the message "0 bytes after a block of size 4 alloc'd" is about #52: void *ret = malloc(T_size_t->size); this pointer is used as a return value allocation then. Some notes on libunistring vs default strings: when I use strnlen instead of u8_mbsnlen and modify the 52-nd line: void *ret = calloc(T_size_t->size, 1); valgrind is happy and no segmentation fault occurs (but it still here with malloc); -- System Information: Debian Release: squeeze/sid APT prefers unstable APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable'), (1, 'experimental') Architecture: i386 (i686) Kernel: Linux 2.6.33.1-ygrex (SMP w/2 CPU cores) Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/bash Versions of packages libffi-dev depends on: ii dpkg 1.15.8.4 Debian package management system ii install-info 4.13a.dfsg.1-5 Manage installed documentation in ii libffi5 3.0.9-2 Foreign Function Interface library libffi-dev recommends no packages. libffi-dev suggests no packages. -- no debconf information
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <limits.h> #include <ffi.h> #include <unistr.h> size_t (* sample)(const uint8_t *, size_t) = u8_mbsnlen; //size_t (* sample)(const char *, size_t) = strnlen; ffi_type *type_init(size_t size) { ffi_type *new = malloc(sizeof(ffi_type)); if (!new) return NULL; new->size = new->alignment = 0; new->type = FFI_TYPE_STRUCT; new->elements = calloc(size + 1, sizeof(ffi_type *)); if (!new->elements) { free(new); return NULL; } size_t i; for (i = 0; i < size; i++) new->elements[i] = &ffi_type_uchar; new->elements[size] = NULL; return new; } int main() { ffi_type *T_size_t = type_init(sizeof(size_t)); if (! T_size_t) return -1; ffi_type **types = calloc( 2, sizeof(ffi_type *)); if (! types) { free(T_size_t->elements); free(T_size_t); return -2; } types[0] = &ffi_type_pointer; types[1] = T_size_t; ffi_cif cif; ffi_status stat = ffi_prep_cif( &cif, FFI_DEFAULT_ABI, 2, T_size_t, types ); void *ret = malloc(T_size_t->size); void **argv = calloc( 2, sizeof(void *)); if ((stat != FFI_OK) || !ret || !argv) { free(types); free(T_size_t->elements); free(T_size_t); return -3; } size_t a = 10; const char *b = "текст"; argv[1] = &a; argv[0] = &b; puts("just before..."); ffi_call(&cif, (void *)sample, ret, argv); /* *(size_t *)ret = (size_t)sample( *(const uint8_t **)(argv[0]), *(size_t *)(argv[1]) ); */ puts("right after!"); printf("ret value: %zu\n", *(size_t *)ret); free(argv); free(ret); free(types); free(T_size_t->elements); free(T_size_t); return 0; }