【问题标题】:After Segfault: Is there a way, to check if pointer is still valid?Segfault 之后:有没有办法检查指针是否仍然有效?
【发布时间】:2010-12-09 17:22:09
【问题描述】:

我计划创建一个日志记录/跟踪机制,它将字符串文字的地址 (const char*) 写入环形缓冲区。这些字符串位于只读数据段中,由预处理器使用__function____file__ 创建。

问题:如果所有指针都有效,是否有可能在 Segfault 之后分析此环形缓冲区内容? “有效”是指它们指向映射的内存区域,取消引用不会导致分段错误。

我正在使用 Linux 2.6.3x 和 GCC 4.4.x。

最好的问候,

查理

【问题讨论】:

    标签: linux gcc g++ segmentation-fault


    【解决方案1】:

    我认为您正在寻找的方法是通过sigaction 处理SIGSEGV 信号。

    void handler(int, siginfo_t *info, ucontext_t *uap)
    {
       /* Peek at parameters here...  I'm not sure exactly what you want to do. */
    }
    
    /* Set up the signal handler... */
    
    struct sigaction sa, old_sa;
    memset(&sa, 0 sizeof(sa));
    
    sa.sa_sigaction = handler;
    sa.sa_flags = SA_SIGINFO;
    
    if (sigaction(SIGSEGV, &sa, &old_sa))
    {
       /* TODO: handle error */
    }
    

    但是请注意,在您自己的进程中捕获SIGSEGV 有点奇怪。该过程可能处于无法恢复的不良状态。您可以针对它执行的操作可能是有限的,而被杀死的进程很可能是一件好事。

    如果您希望它更稳定一点,可以使用sigaltstack 调用,它可以让您指定一个备用堆栈缓冲区,这样,如果您的堆栈完全耗尽,您仍然可以处理SIGSEGV。要使用它,您需要在上面的sa.sa_flags 中设置SA_ONSTACK

    如果您想从另一个进程的安全性中响应SEGV(从而将您自己与表现不佳的段错误代码隔离开来,并使其在检查时不会崩溃),您可以使用ptrace。这个接口比较复杂,有很多不可移植的部分,主要用于编写调试器。但是你可以用它做一些很棒的事情,比如读写进程的内存和寄存器,以及改变它的执行。

    【讨论】:

      【解决方案2】:

      检查取消引用内存区域是否会导致段错误的常用方法是使用read()write()。例如,检查 ptr 指向的前 128 个字节是否可以安全读取:

      int fd[2];
      if (pipe(fd) >= 0) {
          if (write(fd[1], ptr, 128) > 0)
              /* OK */
          else
              /* not OK */
          close(fd[0]);
          close(fd[1]);
      }
      

      (如果区域不可读,write() 将返回 EFAULT 而不是发出信号)。

      如果您想一次测试超过PIPE_BUF 个字节,则需要从管道的读取端读取并丢弃。

      【讨论】:

      • 嗯...我被卡住了,写入常规文件或 fifo 工作正常 - 而写入 /dev/null 总是写入 128 个字节 - 与指针的有效性无关.. .
      • 根据this thread "/dev/null" 不起作用:s
      • @Charly:我已将答案更新为使用pipe(),用于/dev/null 实际上没有进行检查的地方。
      【解决方案3】:

      当然,如果您依赖的堆栈或其他内存已损坏,则可能会出现问题,但任何代码都是如此。

      假设您所依赖的堆栈或其他内存没有问题,并假设您没有调用任何像malloc() 这样不是async-signal safe 的函数,并假设您不尝试返回从您的信号处理程序中,那么从您的信号处理程序中读取或写入您的缓冲区应该没有问题。

      如果您尝试测试特定地址是否有效,可以使用mincore() 等系统调用并检查错误结果。

      【讨论】:

        【解决方案4】:

        一旦您收到段错误,所有赌注都将取消。指针可能有效,也可能已损坏。你只是不知道。您可能能够将它们与有效值进行比较,或者指向环形缓冲区本身的指针可能已损坏。在这种情况下,您可能会得到垃圾。

        【讨论】:

          猜你喜欢
          • 2011-04-20
          • 2011-12-01
          • 2016-04-18
          • 1970-01-01
          • 2011-06-03
          • 1970-01-01
          • 2017-09-02
          • 1970-01-01
          相关资源
          最近更新 更多