qmail segfault alloc() problem on x86_64 and solution
Jan Krueger
2007-02-09 15:10:35 UTC

first my system configuration:
System: Ubuntu Linux 6.06 64bit on AMD x86_64
Compilers: gcc-3.4.6 and gcc-4.0.3
Libc: glibc-2.3.6 and dietlibc-0.31

dietlibc is available from: http://www.fefe.de/dietlibc/
I recommend to use the version from cvs.

The Problem:

When linking qmail against dietlibc, qmail, specifically qmail-rspawn,
becomes unreliable, segfaulting. Problem might appear with glibc to, or
on any other 64bit system, sooner or later, probably later.

Problem verification:

compile and link qmail against dietlibc
[ in the qmail source directory you may need to do:
sed -i 's/extern int read();/#include <unistd.h>/' readwrite.h
sed -i 's/extern int write();//' readwrite.h
echo "diet -Os gcc -Os -D_BSD_SOURCE" > conf-cc
echo "diet gcc -s" > conf-ld

then execute qmail-rspawn:

# ./qmail-rspawn
xSegmentation fault

The Cause:

line 194 in spawn.c:

d = (struct delivery *) alloc((auto_spawn + 10) * \
sizeof(struct delivery));

referencing d later results in Segmentation fault.

When compiling, gcc in this case assumes the return value of alloc() to
be an int, therefore the pointer which is meant to be returned is
truncated to an int.
This can be easily verified by removing the cast in line 194, so:

d = alloc((auto_spawn + 10) * sizeof(struct delivery));

Compilation now exhibits the message:

spawn.c:194: warning: assignment makes pointer from integer without a

The Problem did not show up when linking against glibc, because the
allocator of glibc in this case and on my system configuration returned
an address within the range of an int. However the dietlibc allocator
returned an address not fitting into int and so the address got
truncated resulting in segfault.


Simple, add an:

#include "alloc.h"

at the beginning of every file where alloc() is called.
Now gcc knows for sure that alloc returns char * and no more truncation

Looks like a time bomb to me :)

Jan Krueger
2007-02-09 16:05:09 UTC
Post by Jan Krueger
#include "alloc.h"
at the beginning of every file where alloc() is called.
This would be only in cdb_make.c and spawn.c where it is missing.
I attached a simple patch.