关于C#:打印分段故障原因

print the segmentation fault reason

本问题已经有最佳答案,请猛点这里访问。

假设我有一个导致分段错误的代码。

1
2
char * ptr = NULL;
*ptr ="hello"; /* this will cause a segmentation fault */

如何在运行时打印,分段错误发生在内存中的地址,以及分段错误的原因(访问禁止的内存区域或其他内容)。

我读过核心转储文件,但我不确定它是否是正确的解决方案。

我该怎么做?

另外,我知道我可以通过使用gdb或其他调试器来实现这一点,但目的是通过使用代码和仅使用代码来实现这一点。


如果您想知道原因,可以注册一个信号处理程序,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void handler(int signum, siginfo_t *info, void *context)
{
  struct sigaction action = {
    .sa_handler = SIG_DFL,
    .sa_sigaction = NULL,
    .sa_mask = 0,
    .sa_flags = 0,
    .sa_restorer = NULL
  };

  fprintf(stderr,"Fault address: %p
"
, info->si_addr);
  switch (info->si_code) {
  case SEGV_MAPERR:
    fprintf(stderr,"Address not mapped.
"
);
    break;

  case SEGV_ACCERR:
    fprintf(stderr,"Access to this address is not allowed.
"
);
    break;

  default:
    fprintf(stderr,"Unknown reason.
"
);
    break;
  }

  /* unregister and let the default action occur */
  sigaction(SIGSEGV, &action, NULL);
}

然后你需要在某个地方注册它:

1
2
3
4
5
6
7
8
9
10
11
12
  struct sigaction action = {
    .sa_handler = NULL,
    .sa_sigaction = handler,
    .sa_mask = 0,
    .sa_flags = SA_SIGINFO,
    .sa_restorer = NULL
  };


  if (sigaction(SIGSEGV, &action, NULL) < 0) {
    perror("sigaction");
  }

基本上,当sigsegv被发送时,您注册一个触发的信号,并获得一些附加信息,引用手册页:

1
2
3
4
5
   The following values can be placed in si_code for a SIGSEGV signal:

       SEGV_MAPERR    address not mapped to object

       SEGV_ACCERR    invalid permissions for mapped object

这些映射到出现SEG错误的两个基本原因——要么您访问的页面根本没有映射,要么您不被允许执行您试图执行的任何操作。

这里,在信号处理程序激发之后,它将注销自身并替换默认操作。这将导致无法再次执行的操作,以便被正常路由捕获。这是页面错误(获得SEG错误的前兆)的正常行为,因此像需求分页这样的事情可以工作。


正如这里已经回答的:当我的GCC C++应用程序崩溃时,如何生成堆栈跟踪

您可以(至少在使用Linux/BSD的gcc中)非常容易地做到这一点:

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>


void handler(int sig) {
  void *array[10];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, 10);

  // print out all the frames to stderr
  fprintf(stderr,"Error: signal %d:
"
, sig);
  backtrace_symbols_fd(array, size, 2);
  exit(1);
}

int main(int argc, char **argv) {
  signal(SIGSEGV, handler);   // install our handler

  char * ptr = NULL;
  *ptr ="hello"; /* this will cause a segmentation fault */
}

实例输出:

1
2
3
4
5
6
7
8
# gcc -g -rdynamic -o test test.c
# ./test
Error: signal 11:
0   test                                0x000000010e99dcfa handler + 42
1   libsystem_c.dylib                   0x00007fff95c1194a _sigtramp + 26
2   ???                                 0x0000000000000000 0x0 + 0
3   libdyld.dylib                       0x00007fff8fa177e1 start + 0
4   ???                                 0x0000000000000001 0x0 + 1