Porušení ochrany paměti (též chyba paměťové ochrany, anglicky segmentation fault) je obecně snaha přistoupit k paměti počítače, kterou procesor nemůže fyzicky adresovat. Nastává v případě, kdy hardware upozorní operační systém o nepovoleném přístupu k paměti. Jádro operačního systému na tuto událost obvykle zareaguje nápravným krokem. Například odešle procesu, který chybu vyvolal, signál k jeho ukončení a výpisu paměti (core dump). Za určitých podmínek je možné, aby procesy požádaly o svolení samy se obnovit zavedením vlastní obsluhy signálu.[1]
Na POSIX-kompatibilních systémech chyby sběrnice obvykle vyústí v zaslání signálu SIGBUS procesu, který chybu způsobil. SIGBUS může být také způsoben nějakou obecnou vadou zařízení, kterou počítač detekoval. Chyba sběrnice zřídkakdy znamená, že hardware počítače je fyzicky poškozen – je většinou způsobena programovou chybou ve zdrojovém kódu programu.
Existují dvě hlavní příčiny chyby sběrnice:
CPU všeobecně přistupuje k datům v celé šířce jejich sběrnice po celou dobu. Pro adresování jednotlivých bytů přistupují k paměti v celé šířce jejich sběrnice, potom získanou hodnotu zamaskují a posunou. Systémy tolerují tento neefektivní algoritmus, neboť jde o jednu ze základních funkcí většiny softwarů, obzvláště při zpracování řetězců. Větší jednotky na rozdíl od bytů mohou zahrnovat dvě zarovnané adresy, a tudíž budou vyžadovat více než jedno načtení dat z datové sběrnice. Pro CPU je možné tuto funkci podporovat, ale málokdy je to vyžadováno přímo na úrovni strojového kódu. Návrháři CPU se tedy za normálních okolností implementaci této podpory vyhýbají a místo toho implementují oznámení chyby sběrnice kvůli nezarovnanému přístupu do paměti.
Toto je příklad nezarovnaného přístupu do paměti, napsaný v programovacím jazyce C se AT&T syntaxí pro assembler.
#include <stdlib.h>
int main(int argc, char **argv) {
int *iptr;
char *cptr;
#if defined(__GNUC__)
# if defined(__i386__)
/* Enable Alignment Checking on x86 */
__asm__("pushf\norl $0x40000,(%esp)\npopf");
# elif defined(__x86_64__)
/* Enable Alignment Checking on x86_64 */
__asm__("pushf\norl $0x40000,(%rsp)\npopf");
# endif
#endif
/* malloc() always provides aligned memory */
cptr = (char *) malloc(sizeof(int) + 1);
/* Increment the pointer by one, making it misaligned */
iptr = (int *) ++cptr;
/* Dereference it as an int pointer, causing an unaligned access */
*iptr = 42;
return 0;
}
Kompilace a spuštění příkladu na POSIX-kompatibilním systému na platformě x86:
$ gcc -ansi sigbus.c -o sigbus $ ./sigbus Bus error $ gdb ./sigbus (gdb) r Program received signal SIGBUS, Bus error. 0x080483ba in main () (gdb) x/i $pc 0x80483ba <main+54>: mov DWORD PTR [eax],0x2a (gdb) p/x $eax $1 = 0x804a009 (gdb) p/t $eax & (sizeof(int) - 1) $2 = 1
GDB debugger ukazuje, že hodnota 0x2a je uložena na adresu uloženou v EAX registru, použitím X86 assembleru.
Vypsáním nejméně významných bitů adrset ukazuje, že není zarovnána na velikost slova ("dword" v x86 terminologii).
V tomto článku byl použit překlad textu z článku Segmentation fault na anglické Wikipedii.