“总线错误”消息是什么意思,它与分段错误有什么不同?
当前回答
首先,SIGBUS和SIGSEGV不是特定类型的错误,而是错误组或错误族。这就是为什么您通常会看到一个信号数(si_no)和一个信号代码(si_code)。
它们还取决于操作系统和体系结构,具体是什么导致了它们。
一般来说我们可以这么说。 SIGSEGV与内存映射(权限,无映射)相关,即mmu错误。
SIGBUS是当内存映射成功时,你遇到了底层内存系统的问题(内存不足,该位置没有内存,对齐,smmu阻止访问等),即总线错误。
一个SIGBUS也可以与mmap文件,如果文件从系统中消失,例如,你mmap文件在一个可移动媒体上,它被拔出。
查看平台的一个好地方是siginfo.h标头,以了解信号子类型。 这个页面提供了一个概述。 https://elixir.bootlin.com/linux/latest/source/include/uapi/asm-generic/siginfo.h#L245
/*
* SIGSEGV si_codes
*/
#define SEGV_MAPERR 1 /* address not mapped to object */
#define SEGV_ACCERR 2 /* invalid permissions for mapped object */
#define SEGV_BNDERR 3 /* failed address bound checks */
#ifdef __ia64__
# define __SEGV_PSTKOVF 4 /* paragraph stack overflow */
#else
# define SEGV_PKUERR 4 /* failed protection key checks */
#endif
#define SEGV_ACCADI 5 /* ADI not enabled for mapped object */
#define SEGV_ADIDERR 6 /* Disrupting MCD error */
#define SEGV_ADIPERR 7 /* Precise MCD exception */
#define SEGV_MTEAERR 8 /* Asynchronous ARM MTE error */
#define SEGV_MTESERR 9 /* Synchronous ARM MTE exception */
#define NSIGSEGV 9
/*
* SIGBUS si_codes
*/
#define BUS_ADRALN 1 /* invalid address alignment */
#define BUS_ADRERR 2 /* non-existent physical address */
#define BUS_OBJERR 3 /* object specific hardware error */
/* hardware memory error consumed on a machine check: action required */
#define BUS_MCEERR_AR 4
/* hardware memory error detected in process but not consumed: action optional*/
#define BUS_MCEERR_AO 5
#define NSIGBUS 5
最后需要注意的是,所有信号都可以由用户生成,例如kill。 如果它是用户生成的,那么si_code就是SI_USER。所以特殊源得到负si_codes。
/*
* si_code values
* Digital reserves positive values for kernel-generated signals.
*/
#define SI_USER 0 /* sent by kill, sigsend, raise */
#define SI_KERNEL 0x80 /* sent by the kernel from somewhere */
#define SI_QUEUE -1 /* sent by sigqueue */
#define SI_TIMER -2 /* sent by timer expiration */
#define SI_MESGQ -3 /* sent by real time mesq state change */
#define SI_ASYNCIO -4 /* sent by AIO completion */
#define SI_SIGIO -5 /* sent by queued SIGIO */
#define SI_TKILL -6 /* sent by tkill system call */
#define SI_DETHREAD -7 /* sent by execve() killing subsidiary threads */
#define SI_ASYNCNL -60 /* sent by glibc async name lookup completion */
#define SI_FROMUSER(siptr) ((siptr)->si_code <= 0)
#define SI_FROMKERNEL(siptr) ((siptr)->si_code > 0)
其他回答
段错误是访问不允许访问的内存。它是只读的,你没有权限等等。
总线错误试图访问不可能存在的内存。您使用了一个对系统没有意义的地址,或者该操作的地址类型是错误的。
当根目录为100%时,我得到一个总线错误。
我相信内核会引发SIGBUS 当应用程序显示数据时 数据总线上的不对中。我认为 那是因为大多数[?现代编译器 对于大多数处理器,垫/对齐 为程序员提供的数据 以前的对准问题(至少) 减轻,因此一个人看不见 这些天SIGBUS太频繁(AFAIK)。
来自:这里
这取决于你的操作系统、CPU、编译器以及其他因素。
一般来说,这意味着CPU总线无法完成命令或发生冲突,但这可能意味着一系列事情,具体取决于正在运行的环境和代码。
mmap最小POSIX 7的例子
“总线错误”发生在内核向进程发送SIGBUS时。
一个因为ftruncate被遗忘而产生它的最小示例:
#include <fcntl.h> /* O_ constants */
#include <unistd.h> /* ftruncate */
#include <sys/mman.h> /* mmap */
int main() {
int fd;
int *map;
int size = sizeof(int);
char *name = "/a";
shm_unlink(name);
fd = shm_open(name, O_RDWR | O_CREAT, (mode_t)0600);
/* THIS is the cause of the problem. */
/*ftruncate(fd, size);*/
map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
/* This is what generates the SIGBUS. */
*map = 0;
}
运行:
gcc -std=c99 main.c -lrt
./a.out
在Ubuntu 14.04中测试。
POSIX将SIGBUS描述为:
访问内存对象的未定义部分。
mmap规范说:
在从pa开始的地址范围内引用,并在对象结束后继续为len bytes到整个页面,将导致SIGBUS信号的传递。
shm_open表示它生成大小为0的对象:
共享内存对象的大小为0。
因此,在*map = 0处,我们将触及已分配对象的末端。
ARMv8 aarch64中未对齐的堆栈内存访问
这在:什么是总线错误?对于SPARC,但是在这里我将提供一个更可重复的示例。
你所需要的是一个独立的aarch64程序:
.global _start
_start:
asm_main_after_prologue:
/* misalign the stack out of 16-bit boundary */
add sp, sp, #-4
/* access the stack */
ldr w0, [sp]
/* exit syscall in case SIGBUS does not happen */
mov x0, 0
mov x8, 93
svc 0
然后,该程序在ThunderX2服务器机器上的Ubuntu 18.04 aarch64和Linux内核4.15.0上引发SIGBUS。
不幸的是,我不能在QEMU v4.0.0用户模式上重现它,我不知道为什么。
该错误似乎是可选的,由SCTLR_ELx控制。SA和SCTLR_EL1。SA0字段,我在这里进一步总结了相关文档。