How to catch data-alignment faults on x86 (aka SIGBUS on Sparc)

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP


How to catch data-alignment faults on x86 (aka SIGBUS on Sparc)



Is it somehow possible to catch data-alignment faults even on i386? Maybe by setting a i386 specific machine register or something like that.



On Solaris-Sparc I am receiving a SIGBUS in this case, but on i386 everything is fine.



Environment:



EDIT:
Here is why I am asking this:





It sounds like running your tests in qemu (which can target SPARC) may be faster than running on actual hardware?
– ephemient
Dec 18 '09 at 18:21


qemu





I have never tried qemu, but that sounds interesting. Does that work without some kind of a "System-ROM" or something similar?
– anon
Dec 18 '09 at 19:16





The QEMU project bundles openbios-sparc, which is enough to let qemu-system-sparc like a real machine. There is also qemu-sparc which runs only a single Linux executable under emulation, translating syscalls to the native kernel.
– ephemient
Dec 18 '09 at 22:36


openbios-sparc


qemu-system-sparc


qemu-sparc




6 Answers
6



To expand on Vokuhila-Oliba's answer looking at the "SOF Mis-aligned pointers on x86." thread it seems that gcc can generate code with mis-aligned memory access. AFAIK you don't have any control over this.



Enabling alignment checks on gcc compiled code would be a bad idea. You risk getting SIGBUS errors for good C code.



ReEdited: Sorry about that





@alexandre: I want to get these SIGBUS errors. Not in production code of course, but only for debugging.
– anon
Dec 19 '09 at 11:05





You risk having SIGBUS for code that work on SPARC. It seems that x86 gcc do mis-aligned access in places like variables initialization and I'm not sure you can change that behavior.
– Alexandre Jasmin
Dec 19 '09 at 15:13





@alexandre: you are right! My own second answer shows how to check for alignment failures on i386. But this code works perfectly well on Sparc. On i386 it receives SIGBUS. GCCs behavior for i386 can be changed by using e.g. attribute__((aligned(sizeof(char *)))). But it's not possible to do that globally by setting a global GCC flag. Only individually __attribute settings on a data item are possible. And that's too much effort for the project I am working on :-(
– anon
Dec 19 '09 at 22:25





@Vokuhila-Oliba even if you fix gcc or use another compiler you will have to recompile your libraries or disable alignment checking for each library call your make in your code.
– Alexandre Jasmin
Dec 19 '09 at 23:27





@alexandre: "... even if you fix gcc ... you must recompile all libs": good point! I was just warming up my fingers to patch gcc. Thank you for saving me this effort!
– anon
Dec 20 '09 at 5:03



Meanwhile I found an Intel CPU document addressing this topic.



See Intel® 64 and IA-32 Architectures Software Developer’s Manual.



It seems to be difficult to put all this stuff together. However it doesn't sound like it is completely impossible. The interesting chapter is 4.10.5 Checking Alignment



EDIT (some condensed material from the mentioned document):



page 5-60


Interrupt 17 Alignment Check Exception (#AC)

to enable alignment checking, the following conditions must be true:

AM flag is set(bit 18 of control regisster CR0)
AC flag is set (bit 18 of the EFLAGS)
The CPL is 3 (protected mode or virtual-8086 mode).



additionally - in 14.8.2.6 - Memory Controller Errors are mentioned. I don't know if it is the same only in other words:


table 14-11, Encoding of MMM and CCCC Sub-Fields
Address/Command Error AC 011





Unfortunately, user-mode code all runs in ring 3; the above won't generate exceptions.
– ephemient
Dec 18 '09 at 18:06





I lack knowledge about these CPU "rings". But if a normal program uses ring-3 then it would be good enough.
– anon
Dec 18 '09 at 18:23





Sorry, I misread earlier; "The processor does not generate alignment exceptions when operating at privilege level 0, 1, or 2" definitely leaves ring 3 in the clear.
– ephemient
Dec 18 '09 at 22:39





Too bad CR0 can't be modified in user-mode. You'll need to get your OS to cooperate if you want to set the AM flag in CR0.
– Adam Rosenfield
Dec 19 '09 at 5:49



I have found a very simple solution on SOF! See: Mis-aligned pointers on x86.


int main(int argc, char **argv)
{
# if defined i386
/* EDIT: enable AC check */
asm("pushf; "
"orl $(1<<18), (%esp); "
"popf;");
# endif

char d = "12345678"; /* yep! - causes SIGBUS even on Linux-i386 */
return 0;
}



But I must confess that I do not understand why the assignment



char d = "12345678";



is assumed to be mis-aligned?



EDIT:



on the SPARC machine there is no SIGBUS on the line of assignment to char d.



Intel are very big on supporting unaligned loads. If I had to detect such loads on an Intel platform, I think I would have to modify valgrind to treat unaligned loads as errors. Such a modification is not trivial, but valgrind was designed with the idea in mind that users could create new 'tools'. I think a simple modification to the memcheck tool would detect your unaligned references. And the error reporting is really very nice.


valgrind


memcheck



Many years later: if your gcc/clang is new enough (GCC 4.9, clang 3.3?) you may be able to build your code with the undefined behaviour sanitizer (-fsanitize=undefined) to get warnings about misaligned accesses on a given platform (but bear in mind different platforms have different alignment requirements, different compilers will choose different layouts etc). See https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html and https://developers.redhat.com/blog/2014/10/16/gcc-undefined-behavior-sanitizer-ubsan/ for details.


-fsanitize=undefined



Intel built in unaligned transfers from the start - it was one of the selling points when x86 was brand new. I understand your reasons for wanting to trap unaligned access, but I don't think it's possible.



Edit: very glad to be proven wrong.





you where not completely wrong. Although SIGBUS can be forced even on i386 it doesn't help that much. That's because on the SPARC a "stack mis-alignment" is not considered harmful and does not cause a SIGBUS. But on i386 it causes SIBGUS even for a harmless "stack mis-alignment" when the AC flag is set.
– anon
Dec 19 '09 at 22:35






By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Popular posts from this blog

Keycloak server returning user_not_found error when user is already imported with LDAP

PHP parse/syntax errors; and how to solve them?

How to scale/resize CVPixelBufferRef in objective C, iOS