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;
}

Reply via email to