No, EXC_BAD_ACCESS
不等于SIGSEGV
.
EXC_BAD_ACCESS
是 Mach 例外(Mach 和 xnu 的组合组成了 Mac OS X 内核),而SIGSEGV
是一个 POSIX 信号。当崩溃发生且原因如下时EXC_BAD_ACCESS
,通常信号会立即在括号中报告:例如,EXC_BAD_ACCESS(SIGSEGV)
。然而,还有另一种 POSIX 信号可以与EXC_BAD_ACCESS
: It is SIGBUS
,报告为EXC_BAD_ACCESS(SIGBUS)
.
SIGSEGV
当读取/写入根本未映射到内存映射中的地址时最常见,例如NULL
指针,或尝试写入只读内存位置(如上面的示例所示)。SIGBUS
另一方面,即使对于进程具有合法访问权限的地址也可以看到。例如,SIGBUS
可以打击敢于使用假设对齐地址的指令从未对齐的内存地址加载/存储到未对齐的内存地址的进程,或者尝试写入它没有对齐的页面的进程特权级别这样做。
Thus EXC_BAD_ACCESS
最好可以理解为两者的集合SIGSEGV
and SIGBUS
,并指所有错误访问内存的方式(无论是因为所述内存不存在,还是存在但未对齐、特权或诸如此类),因此得名:异常——访问错误.
为了让您大饱眼福,这里是代码,在xnu-1504.15.3 (Mac OS X 10.6.8 build 10K459)
内核源代码、文件bsd/uxkern/ux_exception.c
从行开始429
,翻译过来就是EXC_BAD_ACCESS
到任一SIGSEGV
or SIGBUS
.
/*
* ux_exception translates a mach exception, code and subcode to
* a signal and u.u_code. Calls machine_exception (machine dependent)
* to attempt translation first.
*/
static
void ux_exception(
int exception,
mach_exception_code_t code,
mach_exception_subcode_t subcode,
int *ux_signal,
mach_exception_code_t *ux_code)
{
/*
* Try machine-dependent translation first.
*/
if (machine_exception(exception, code, subcode, ux_signal, ux_code))
return;
switch(exception) {
case EXC_BAD_ACCESS:
if (code == KERN_INVALID_ADDRESS)
*ux_signal = SIGSEGV;
else
*ux_signal = SIGBUS;
break;
case EXC_BAD_INSTRUCTION:
*ux_signal = SIGILL;
break;
...
编辑与您的另一个问题相关的内容
请注意例外这里并不是指语言级别的异常,也不是人们可以用语法糖捕获的类型,例如try{} catch{}
块。这里的异常是指 CPU 在程序中遇到某些类型的错误(它们可能是致命的,也可能不是致命的)时的操作,例如需要外部干预的空指针取消引用。
当这种情况发生时,CPU 被称为raise通常称为例外 or an 打断。这意味着 CPU 会保存它正在执行的操作(context)并处理特殊情况。
为了处理这种异常情况,CPUnot开始执行any“异常处理”代码(catch
-blocks 或类似的东西)在你的应用程序中。它首先通过开始执行内核提供的一段代码(称为中断服务程序。这是一段代码,用于确定哪个进程发生了什么以及如何处理它。因此,操作系统有机会判断情况并采取所需的操作。
它对无效内存访问(例如空指针取消引用)执行的操作是用以下命令向有罪进程发出信号:EXC_BAD_ACCESS(SIGSEGV)
。它对未对齐的内存访问所做的操作是向有罪进程发出信号EXC_BAD_ACCESS(SIGBUS)
。还有许多其他异常情况和相应的操作,并非所有情况都涉及信号。
现在我们回到了您的程序的背景。如果您的程序收到SIGSEGV
or SIGBUS
信号,它将调用信号处理程序为该信号安装的,如果没有则安装默认的。人们很少安装自定义处理程序SIGSEGV
and SIGBUS
默认处理程序会关闭您的程序,因此您通常会看到您的程序被关闭。
因此,这种异常与那种异常完全不同throw
s in try{}
-块和catch{}
es. Those异常纯粹在应用程序内处理,不涉及操作系统at all。这里发生的是throw
声明只是一个华丽的跳转到最里面catch
处理该异常的块。当异常在堆栈中冒泡时,它unwinds它后面的堆栈,根据需要运行析构函数等。