为什么系统调用返回EFAULT而不是发送段错误?

时间:2012-03-07 16:15:06

标签: c segmentation-fault posix standards signals

要清楚,这是一个设计而不是一个实现问题

我想知道POSIX为什么会这样做的理由。当给定无效的内存位置时POSIX系统调用返回EFAULT而不是崩溃用户空间程序(通过发送sigsegv),这使得它们的行为与用户空间函数不一致。

为什么呢?这不是隐藏内存错误吗?这是历史错误还是有充分理由呢?

2 个答案:

答案 0 :(得分:4)

因为系统调用是由内核而不是用户程序执行的 - 当系统调用发生时,用户进程停止并等待内核完成。

当然,内核本身不允许出错,因此必须手动检查用户进程提供的所有地址区域。如果其中一个检查失败,则系统调用将失败并显示EFAULT。所以在这种情况下,分段错误实际上并没有发生 - 内核明确地检查以确保所有地址都是有效的。因此,没有信号被发送是有道理的。

此外,如果 发送信号,则内核无法将有意义的程序计数器附加到信号上,当系统调用时,用户进程实际上并未执行运行。这意味着用户进程无法生成正常的诊断,重启失败的指令等等。

总结:主要是历史,但推理有实际的逻辑。与EINTR一样,这并不会减少对它的刺激。

答案 1 :(得分:1)

那么,你想要发生什么?系统调用是对系统的请求。如果你问:“到慕尼黑的渡轮何时离开?”你想让程序崩溃,或者使用errno = ENOHARBOR获得return = -1?如果您要求系统将您的车放入您的手提包中,您是想要将手提包销毁,还是将errno设置为EBAGTOOSMALL返回-1?

有一个技术细节:在系统调用之前或之后,在进入/离开系统调用时必须转换(复制)来自/来自user / system -land的参数。主要出于安全原因,系统非常不愿意写入用户空间。 (Linux有一个copy_to_user_space函数(反之亦然),它在进行实际复制之前检查凭据


  

为什么呢?这不是隐藏内存错误吗?“

恰恰相反。它允许您的程序处理错误(在这种情况下不可能),并优雅地终止。但是程序必须检查系统调用的返回值并检查errno。在SIGSEGVE的情况下,你的程序很少,所以将EINVAL映射到SIGSEGVE会是一个坏主意。

系统调用旨在始终返回(或无限期地阻止......),无论它们是成功还是失败。

技术方面可能是(分段错误,buserror,浮点异常......)(通常)由硬件中断生成。