Re: [dspam-users] bug fix for dspam 3.6.0 Bus error on sparc64 linux hash_drv

From: Nicolas Zin <n.zin@restosducoeur.asso.fr>
Date: Mon Oct 24 2005 - 13:24:49 EDT

Disclaimer: a bit long and technical mail! beware.
Maybe we can talk off mailing list, to not bother everybody.

Jonathan Zdziarski a écrit :

> ...and each record, of course.
>
> Jonathan
>
>
> On Oct 24, 2005, at 11:27 AM, Jonathan Zdziarski wrote:
>
>> What would we need to do to make that work, just adjust the size of
>> the header to be a multiple of 8 bytes? sorry, i'm not very familiar
>> with alignment.
>
Something like this. The bug arise because on some 64 bit arch, 64
operation act on 64 bit aligned offset (because they act on a multiple
of their size), that is the whole point as far as I understand.

To come back to the code, if i read correctly the code (stop me if I'm
wrong) the problem is that on disk you put a hash_drv_header_t first on
the file and after, hash_drv_spam_record_t structures. Like:

+---------+----+----+----+
|header |data|data|data|
+---------+----+----+----+

When you mmap it on memory, the file points to an area like 0x70a80000,
so the first structure, the header structure points to 0x70a80000.
But because for gcc the header is 9x4 octets, the following structure,
is not 8 byte aligned. Indeed all following datas (whose structure
hash_drv_spam_record_t is 16 byte long) are all 4 bytes aligned but not
8 bytes aligned (0x70a80000+sizeof(struct hash_drv_header_t)+ x *
sizeof(struct hash_drv_spam_record_t)= 0x70a80024,
0x70a80034,0x70a80044...), so if you copy the value of hashcode, it try
to access to a not 8byte aligned address: 0x70a80024, and make a bus error.

Several tricks:

A/ position hashcode on a 8 bytes align address when mounted by mmap
We could position the hashcode in the structure to be well aligned like:
typedef struct _hash_drv_spam_record
{
  long nonspam;
  unsigned long long hashcode;
  long spam;
} *hash_drv_spam_record_t;

I didn't try, and I think it will not work, gcc will still align
hashcode, on what it thinks will be a 8 byte aligned.

B/ make the header 8 bytes aligned compliant, to let the following
record 8 bytes compliant
I tried before posting my patches, another trick a bit more elegant
IMHO, I had a "long" to the hash_drv_header_t, like:
typedef struct _hash_drv_header
{
  unsigned long hash_rec_max;
  struct _ds_spam_totals totals;
  long garbage;
} *hash_drv_header_t;

Like this, the structure is not 9x4 octets, but 10x4 octets, and so a
multiple of 8 bytes. hash_drv_spam_record_t is already a multiple of 8
bytes, so it doesn't need to be modified.
In that scenario I didn't have to touch to the rest of the code.

C/ let gcc make the header 8 byte aligned.
When gcc pack a structure, it aligns it on the biggest of its element.
Try for example:
------------
#include <stdio.h>

struct a {
long long a;
int b;
};

struct b {
long a;
long c;
int b;
};

int main(int argc,char *argv[]) {
        printf("size: %d %d\n",sizeof(struct a),sizeof(struct b));
        return 0;
}
------------

So another way to try is to have a header structure like:
typedef struct _hash_drv_header
{
  unsigned long long hash_rec_max;
  struct _ds_spam_totals totals;
} *hash_drv_header_t;

which has the benefit that, if you modify the _ds_spam_totals structure,
the header structure will always be 8 byte aligned.
gcc has also "attributes" to change the packing behaviour, but I didn't
manage to see an option to tell him "pack it has a 8 bytes".
I would recommend maybe this last option, if you want to align your
structures. I have not tried, but I can if you want.

Hope that I didn't lost anybody by the way :-)

/nicolas

PS: if you come with a 128bit processor, you will not run into trouble,
because you don't use 128 bit integer ;-)
Received on Mon Oct 24 13:22:59 2005

This archive was generated by hypermail 2.1.8 : Wed Oct 26 2005 - 00:00:01 EDT