C-有什么方法可以保证segfault



我知道segfault是未定义行为的常见表现。但是我有两个小问题:

  1. 都是segfaults不确定的行为吗?

  2. 如果没有,是否有任何方法可以确保segfault?

什么是分割故障?比我的问题更一般,没有答案回答我的任何问题。

段故障仅表示您对内存无效访问 - 要么是因为请求的地址没有映射(映射错误),要么是因为您don dont具有访问权限的权限(访问错误)。

  1. 有打算的分段故障。一个这样的示例可以在此处找到 - 为了检测给定功能的写作内容,故意播放记忆页的迷你应用程序。

  2. 最简单的方法是使用raise函数。

来源:

#include <signal.h>    
int main() {
    raise(SIGSEGV);
    return 0;
}
  1. 所有segfaults都是未定义的行为吗?

这个问题比看起来更棘手,因为"未定义的行为"是对C源程序的描述,也是在"抽象机器"中运行C程序的结果,该程序一般描述了C程序的行为;但是"分割故障"是特定操作系统的可能行为,通常是在特定CPU功能的帮助下。

C标准对细分故障一无所知。它确实说的一件几乎相关的事情是,如果程序执行没有不确定的行为,那么实际实现程序的执行将与抽象机的执行相同。和"可观察行为"定义为包括对挥发性对象的访问,写入文件中的数据以及交互式设备的输入和输出。

如果我们可以假设"分割故障"始终阻止程序的进一步操作,则只有在所有可观察到的行为都按预期完成后,才能发生任何不确定行为的分割故障。(但是请注意,有效的优化有时会导致事件与明显的优化发生的顺序不同。)

因此,尽管没有不确定的行为(根据C标准),但程序会导致细分故障(对于操作系统),但对于真实的编译器和OS并没有多大意义,但我们不能统治完全。

,但所有这些都假设了完美的计算机。如果RAM不好,则可能会更改预期的地址值。甚至有很少但可衡量的事件,宇宙射线可以在否则好的RAM中有所改变。类似的软错误可能会导致分割故障(在"分割故障"是一件事的系统上),对于任何完美编写的C程序,在任何实现或输入上都没有任何不确定的行为。

  1. 如果没有,是否有任何方法可以确保segfault?

取决于上下文,以及"确保"的含义。

您可以编写一个C程序,该程序总是会导致segfault?不,因为有些计算机甚至可能没有这样的概念。

您可以编写一个C程序,该程序在计算机上可能总是会导致segfault?不,因为在某些情况下,有些编译器可能会做一些事情来避免实际问题。而且,由于程序的行为不确定,因此不引起segfault与导致segfault的结果一样有效。特别是,您可能会遇到的一个真正的障碍,即使做一些简单的事情,例如故意删除无效指针值,是编译器的优化有时会假设输入和逻辑总是会出现,以免不确定的行为发生,因为这是可以的,因为这是可以的,因为这是可以的对于确实会导致不确定行为的输入的程序所说的话。

了解有关一个特定操作系统以及CPU,处理内存,有时会生成分段故障的详细信息,您能否编写始终会导致segfault的汇编指令?当然,如果Segfault处理根本没有任何价值。您可以编写一个C程序,该程序会以大致相同的方式触发segfault?很可能。

您永远不会出错。

int main() {
  int *a = 0;
  *a = 0;
  return 0;
}

正如评论正确地提及的那样,这将在100%的时间内工作,并且是平台特定的。但是它应该在大多数常见的平台中起作用。

假设平台完全支持segfaults,这里有一些可能性:

  • 使用raise。这将产生明显不同的siginfo_t,但通常无关紧要。
  • 取消非易失性指针。这很可能被优化为"无法到达"。
  • 放弃挥发性指针。这应该防止编译器优化访问。
  • 使用asm volatile并取消指针。请确保包括后来使用的伪造输出,否则编译器仍然可以执行不必要的优化。这需要每个平台的特殊代码。
  • 构建一个内核模块,该内核模块直接生产具有适当siginfo_tSIGSEGV。假设内核模块甚至可以加载可以加载(甚至是编译)。

如果我们要删除指针,我们是否:

  • 阅读或
  • 通过它写或
  • 两者?

,应该是什么指针?

  • NULL是一个受欢迎的选择,但有时可以映射该页面。如今,注重安全意识的内核通常不允许这一点。
  • 使用有效但错位的指针。这是高度依赖性的,并且可能产生不同的siginfo_t。也许甚至是SIGBUS之类的东西。
  • 使用跨越页面的未对准指针,其中一个页面是未封闭或保护的,如下所示。
  • 通过保护您正在尝试的访问的保护,请致电mmap。我不记得此siginfo_t是否可以区分。可以比赛,但是只有该程序中的其他一些线程是敌对的。mmap也可能失败。
  • 呼叫mmap,然后立即进行munmap,然后取消指针。在具有信号阻塞的单线读取程序中,这可以产生一个保证不映射的地址。但是,它可能会在多线程程序中进行比赛,并且初始mmap可能会失败。
  • 在循环中调用mmap,直到失败,因为您已经用尽了内核对映射的内存区域的64K限制。然后解析/proc/self/maps,找到一个未涵盖的地址。如果其他线程当前是munmap ING,这可能是可能的。如果其他线程当前是mmap,则在您的segfault杀死该过程之前,它们可能会以神秘的方式失败。

总而言之,没有完美的可靠/便携式方法,但是有很多足够好的。

相关内容

  • 没有找到相关文章

最新更新