bus error & Segmentation fault

2011-09-20  刘旸 

今天在linux上写个小程序检测coredump文件是否能够正常生成,结果意外发现出现的是bus error,而不是经常看见的segmentation fault. 好奇之下查询了一下维基百科,原来bus error通常是由于对未对齐的读或者写引起的。下面是维基百科的原文和例子:Bus error

Bus errors are usually signaled with the SIGBUS signal, but SIGBUS can also be caused by any general device fault that the computer detects. A bus error rarely means that the computer hardware is physically broken - it is normally caused by a bug in a program's source code.

There are two main causes of bus errors:

non-existent address The CPU is instructed by software to read or write a specific physical memory address. Accordingly, the CPU sets this physical address on its address bus and requests all other hardware connected to the CPU to respond with the results, if they answer for this specific address. If no other hardware responds, the CPU raises an exception, stating that the requested physical address is unrecognized by the whole computer system. Note that this only covers physical memory addresses. Trying to access an undefined virtual memory address is generally considered to be a segmentation fault rather than a bus error, though if the MMU is separate, the processor can't tell the difference. unaligned access Most CPUs are byte-addressable, where each unique memory address refers to an 8-bit byte. Most CPUs can access individual bytes from each memory address, but they generally cannot access larger units (16 bits, 32 bits, 64 bits and so on) without these units being "aligned" to a specific boundary. For example, if multi-byte accesses must be 16 bit-aligned, addresses 0, 2, 4, and so on would be considered aligned and therefore accessible, while addresses 1, 3, 5, and so on would be considered unaligned. Similarly, if multi-byte accesses must be 32-bit aligned, addresses 0, 4, 8, 12, and so on would be considered aligned and therefore accessible, and all addresses in between would be considered unaligned. Attempting to access a unit larger than a byte at an unaligned address can cause a bus error.

CPUs generally access data at the full width of their data bus at all times. To address bytes, they access memory at the full width of their data bus, then mask and shift to address the individual byte. This is inefficient, but tolerated as it is an essential feature for most software, especially string processing. Unlike bytes, larger units can span two aligned addresses and would thus require more than one fetch on the data bus. It is possible for CPUs to support this, but this functionality is rarely required directly at the machine code level, thus CPU designers normally avoid implementing it and instead issue bus errors for unaligned memory access.

Segmentation/Page fault
Example of human generated signal

A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-only location, or to overwrite part of the operating system).

Segmentation is one approach to memory management and protection in the operating system. It has been superseded by paging for most purposes, but much of the terminology of segmentation is still used, "segmentation fault" being an example. Some operating systems still have segmentation at some logical level although paging is used as the main memory management policy.

On Unix-like operating systems, a signal called SIGSEGV is sent to a process that accesses an invalid memory address. On Microsoft Windows, a process that accesses invalid memory receives the STATUS_ACCESS_VIOLATION exception.

Examples [edit] Bus error example

This is an example of un-aligned memory access, written in the C programming language.

#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 = 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; }

Compiling and running the example on Linux on x86 demonstrates the error:

$ 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

The GDB debugger shows that the immediate value 0x2a is being stored at the location stored in the EAX register, using X86 assembly language. This is an example of register indirect addressing.

Printing the low order bits of the address shows that it is not aligned to a word boundary ("dword" using x86 terminology).

[edit] Segmentation fault example

Here is an example of ANSI C code that should create a segmentation fault on platforms with memory protection:

int main(void) { char *s = "hello world"; *s = 'H'; }

When the program containing this code is compiled, the string "hello world" is placed in the section of the program binary marked as read-only; when loaded, the operating system places it with other strings and constant data in a read-only segment of memory. When executed, a variable, s, is set to point to the string's location, and an attempt is made to write an H character through the variable into the memory, causing a segmentation fault. Compiling such a program with a compiler that does not check for the assignment of read-only locations at compile time, and running it on a Unix-like operating system produces the following runtime error:

655°/6556 人阅读/0 条评论 发表评论

登录 后发表评论