“EXC_BAD_ACCESS”与“分段错误”。两者实际上相同吗?

2024-05-23

在我的前几个虚拟应用程序(用于学习时练习)中,我遇到了很多EXC_BAD_ACCESS,这以某种方式告诉我错误访问是:您正在触摸/访问一个不应该的对象,因为它尚未分配或释放,或者只是您无权访问它。

查看此示例代码,该代码存在访问错误问题,因为我正在尝试修改const :

-(void)myStartMethod{
    NSString *str = @"testing";
    const char *charStr = [str UTF8String];
    charStr[4] = '\0'; // bad access on this line.
    NSLog(@"%s",charStr);
} 

虽然分段错误说:分段错误是由于访问“不属于您”的内存而导致的一种特定错误。它是一种辅助机制,可以防止您破坏内存并引入难以调试的内存错误。每当你遇到段错误时,你就知道你的内存出了问题(更多描述here https://stackoverflow.com/questions/2346806/what-is-segmentation-fault.

我想知道两件事。 一, 我说得对吗objective-C's EXC_BAD_ACCESS?我说得对吗?

Second, Are EXC_BAD_ACCESS and Segmentation fault同样的事情,苹果只是临时起个名字?


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默认处理程序会关闭您的程序,因此您通常会看到您的程序被关闭。

因此,这种异常与那种异常完全不同throws in try{}-块和catch{}es. Those异常纯粹在应用程序内处理,不涉及操作系统at all。这里发生的是throw声明只是一个华丽的跳转到最里面catch处理该异常的块。当异常在堆栈中冒泡时,它unwinds它后面的堆栈,根据需要运行析构函数等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

“EXC_BAD_ACCESS”与“分段错误”。两者实际上相同吗? 的相关文章