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

Reply via email to