GCC i Clang mají vestavěný UndefinedBehaviorSanitizer. Jedna z těchto kontrol, alignment
, lze povolit pomocí -fsanitize=alignment
. Vyšle kód pro kontrolu zarovnání ukazatele za běhu a přeruší se, pokud jsou nezarovnané ukazatele dereferencovány.
Viz online dokumentaci na adrese:
- https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
Je to složité a osobně jsem to nedělal, ale myslím, že to můžete udělat následujícím způsobem:
CPU x86_64 (konkrétně jsem zkontroloval Intel Corei7, ale myslím, že i ostatní) mají čítač výkonu MISALIGN_MEM_REF, který počítá nesprávně zarovnané reference paměti.
Nejprve tedy můžete spustit svůj program a použít nástroj „perf“ pod Linuxem, abyste získali počet chybných přístupů, které váš kód provedl.
Ošemetnějším a zajímavějším hackem by bylo napsat modul jádra, který naprogramuje čítač výkonu tak, aby generoval přerušení při přetečení a přiměl ho k přetečení prvního nezarovnaného načtení/úložiště. Odpovězte na toto přerušení v modulu jádra, ale odešlete signál vašemu procesu.
To ve skutečnosti změní x86_64 na jádro, které nepodporuje nezarovnaný přístup.
To však nebude jednoduché – kromě vašeho kódu používají systémové knihovny také nezarovnané přístupy, takže bude složité je oddělit od vašeho vlastního kódu.
Právě jsem četl otázku Způsobuje nezarovnaný přístup k paměti vždy chyby sběrnice? který odkazoval na článek Segmentation Fault na Wikipedii.
V článku je nádherná připomínka poměrně neobvyklých příznaků AC procesorů Intel aka Alignment Check.
A zde je návod, jak to povolit (z Wikipedia's Bus Error, s opravenou chybou clobber red-zone pro x86-64 System V, takže je to bezpečné na Linuxu a MacOS a převedeno z Basic asm, což není nikdy dobrý nápad uvnitř funkcí:chcete, aby byly změny AC objednány pomocí přístupů do paměti.
#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\n orl $0x40000,(%%esp)\n popf" ::: "memory");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("add $-128, %%rsp \n" // skip past the red-zone, in case there is one and the compiler has local vars there.
"pushf\n"
"orl $0x40000,(%%rsp)\n"
"popf \n"
"sub $-128, %%rsp" // and restore the stack pointer.
::: "memory"); // ordered wrt. other mem access
# endif
#endif
Po povolení to funguje podobně jako nastavení zarovnání ARM v /proc/cpu/alignment
, viz odpověď Jak zachytit nezarovnaný přístup k paměti? pro příklady.
Pokud navíc používáte GCC, doporučuji povolit -Wcast-align
varování. Při sestavování pro cíl s přísnými požadavky na zarovnání (například ARM) bude GCC hlásit umístění, která mohou vést k nezarovnanému přístupu k paměti.
Všimněte si však, že ručně psaný asm libc pro memcpy a další funkce bude stále provádět nezarovnané přístupy, takže nastavení AC často není praktické na x86 (včetně x86-64). GCC někdy vysílá asm, který umožňuje nezarovnané přístupy, i když to váš zdroj nedělá, např. jako optimalizace pro kopírování nebo nulování dvou sousedních prvků pole nebo členů struktury najednou.