Reputation: 12960
I have inherited a very ancient (start of 2000s) Code base that consists of a driver and a kernel module and it crashes for some combinations of compiler flags/architectures. At some point an offset is incorrect for an unknown reason and when I skimmed the code base I found a lot of unaligned access and wanted to clean up this part to remove these potential issues. Example:
uint32_t* p = ....; // <-- odd address on right side.
uint32_t b = *p + 1;
I know that current processors handle such cases without noticeable delays, and I had problems finding hardware that would trigger a BUS error (I once had a RPi 1 that would produce bus errors when setting /proc/cpu/alignment to 4). I wanted to make sure the compiler generates code that correctly access the memory. My first draft for reading a 32 bit integer and converting it from network to host byte order (there was already a macro for that) for an unaligned address was thus (dest and src are pointers to some memory):
#define SWAP32(dest, src) \
do { \
uint32_t tmp_ = 0; \
memcpy(&tmp_, (const char*)(src), sizeof(tmp_)); \
tmp_ = bswap_32(tmp_); \
memcpy((char*)(dest), &tmp_, sizeof(tmp_)); \
} while(0)
I then wanted to create a macro to wrap pointer accesses for other cases that were not yet wrapped in a macro and came up with the following solution (sample contains code to make it compile):
#include <stdint.h>
#include <stdio.h>
struct __attribute__((packed)) unaligned_fix_32 { uint32_t n; };
#define GET32(x) ((struct unaligned_fix_32*)(x))->n
int main(int argc, char* argv[])
{
char mem[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
uint32_t n = GET32(&mem[1]);
printf("0x%8.8x\n", n);
}
My goal is to wrap pointer accesses inside this macro everywhere. The idea is that, knowing the struct is packed, the compiler will generate code that accesses memory in a way that avoids a potential bus error on architectures that cannot access unaligned memory.
EDIT: I changed my code to the following new version:
static inline uint32_t get_be_unaligned_u32(const void* p)
{
uint32_t u32;
memcpy(&u32, (const char*)p, sizeof(u32));
return bswap_32(u32);
}
#define GET32(src) get_be_unaligned_u32(src)
Please answer questions also for the new version:
-fsanitize=alignment
produces the proper exceptions without the attribute packed, but the generated assembler simply checks addresses with & 0x3
and raises a trap if it is not zero.Upvotes: 0
Views: 415