Can someone provide an example were casting a pointer from one type to another fails due to mis-alignment?
In the comments to this answer, bothie states that doing something like
char * foo = ...;
int bar = *(int *)foo;
might lead to errors even on x86 if alignment-checking is enabled.
I tried to produce an error condition after setting the alignment-check flag via set $ps |= (1<<18) in GDB, but nothing happened.
What does a working (ie non-working ;)) example look like?
None of the code snippets from the answers fail on my system – I’ll try it with a different compiler version and on a different pc later.
Btw, my own test code looked like this (now also using asm to set AC flag and unaligned read and write):
#include <assert.h>
int main(void)
{
#ifndef NOASM
__asm__(
"pushf\n"
"orl $(1<<18),(%esp)\n"
"popf\n"
);
#endif
volatile unsigned char foo[] = { 1, 2, 3, 4, 5, 6 };
volatile unsigned int bar = 0;
bar = *(int *)(foo + 1);
assert(bar == 0x05040302);
bar = *(int *)(foo + 2);
assert(bar == 0x06050403);
*(int *)(foo + 1) = 0xf1f2f3f4;
assert(foo[1] == 0xf4 && foo[2] == 0xf3 && foo[3] == 0xf2 &&
foo[4] == 0xf1);
return 0;
}
The assertion passes without problems, even though the generated code definitely contains the unaligned access mov -0x17(%ebp), %edx and movl $0xf1f2f3f4,-0x17(%ebp).
So will setting AC trigger a SIGBUS or not? I couldn’t get it to work on my Intel dual core laptop under Windows XP with none of the GCC versions I tested (MinGW-3.4.5, MinGW-4.3.0, Cygwin-3.4.4), whereas codelogic and Jonathan Leffler mentioned failures on x86…
There is an additional condition, not mentioned, for EFLAGS.AC to actually take effect. CR0.AM must be set to prevent INT 17h from tripping on older OSes predating the 486 that have no handler for this exception. Unfortunately, Windows do not set it by default, you need to write a kernel-mode driver to set it.