Hi All,
In a much larger application, I was getting a weird segfault that an
assignment to a temporary variable fixed. I distilled the example into
the attached "test_case.c". When I run test_case.c under valgrind I
get a memory read error, and it segfaults with electric fence, but I'm
not actually able to get a true segfault. However, I am pretty sure
that the same issue was causing the segfault in my application.
>From my really limited assembly knowledge, it looks that on 64 bit
machines gcc is trying to do a full 8 byte read into the register
followed by a 2 byte shift ( instead of 4 then 2 byte read ). If the
two extra bytes are out of bounds it will segfault. This explains why
I get the sporadic segfaults in my bigger application ( where I can
actually be at the page boundary ), but not in the test case.
This only occurs on 64 bit machines, and my gcc version info is:
nboley@ingvas:~/Desktop$ gcc -v
Using built-in specs.
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro
4.4.4-14ubuntu5'
--with-bugurl=file:///usr/share/doc/gcc-4.4/README.Bugs
--enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr
--program-suffix=-4.4 --enable-shared --enable-multiarch
--enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix
--with-gxx-include-dir=/usr/include/c++/4.4 --libdir=/usr/lib
--enable-nls --with-sysroot=/ --enable-clocale=gnu
--enable-libstdcxx-debug --enable-objc-gc --disable-werror
--with-arch-32=i686 --with-tune=generic --enable-checking=release
--build=x86_64-linux-gnu --host=x86_64-linux-gnu
--target=x86_64-linux-gnu
Thread model: posix
gcc version 4.4.5 (Ubuntu/Linaro 4.4.4-14ubuntu5)
Best,
Nathan Boley
#include <stdio.h>
#include <stdlib.h>
/* Does NOT cause memory error */
typedef struct __attribute__((__packed__))
{
unsigned short chr;
unsigned int loc;
} GENOME_LOC_TYPE_2;
/* Causes memory error */
typedef struct __attribute__((__packed__))
{
unsigned chr :16;
unsigned loc :32;
} GENOME_LOC_TYPE;
void
print_mapped_location( GENOME_LOC_TYPE loc )
{
printf( "%i\n", loc.loc );
}
int main( int argc, char* argv )
{
char* data;
data = malloc(12*sizeof(char));
GENOME_LOC_TYPE* gen_array
= (GENOME_LOC_TYPE*) data;
gen_array[0].loc = 0;
gen_array[1].loc = 1;
/* Make sure the structure is actually 6 bytes */
printf("Gen Loc Type Size: %zu\n", sizeof(GENOME_LOC_TYPE) );
/* Works fine. */
printf( "%i\n", gen_array[1].loc );
/* Works fine */
GENOME_LOC_TYPE loc = gen_array[1];
print_mapped_location( loc );
/* Causes valgrind error */
/* Cause -lefence segfault */
print_mapped_location( gen_array[1] );
free( data );
}