Discussing the nuts and bolts of software development

Friday, July 11, 2008

 

Alignment Matters

When do these two snippets behave differently?


void* p = something();
int i = *(int*)p;


int i;
void* p = something();
memcpy(&i, p, sizeof(int));


Answer: when 'something' returns a value that's not a multiple of "sizeof(int)".

Some processor architectures only allow loading memory into N-byte registers from memory addresses that are a multiple of N (e.g. multiple of 4 for 32-bit registers). Using misaligned addresses can have some various interesting consequences, depending on the CPU; I've heard of at least these:

Last week, I got lucky: I discovered that the MIPS32 CPU on the phone I was programming falls in the "crash" category. (why lucky? because an "address load exception" message is much easier to debug than some corrupted data)

Usually, we don't have to worry about such alignment issues; the compiler and runtime make sure that all objects it allocates go at addresses that have the right alignment for their type (e.g. malloc must return memory "suitably aligned" for all possible types).

Trouble comes when we lie to the compiler, such as telling it by a cast that "p" points to an "int" when such is not the case. This is what happened to me: I was parsing a file, and the 4-byte-value-that-should-be-put-in-an-int followed an arbitrary-length string. It ended up on an odd address, and boom. (Here's another way I was lucky: it COULD have been a nice multiple of 4 in all my tests, only to come out odd on a client's desk)

Functions like memcpy, of course, are required to work with all addresses (as expressed by taking void* parameters, which require no cast).

Lesson of the day? Don't lie to your compiler!
(alternate lesson: "casts: evil AND chaotic"?)

Labels: , ,


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?