我希望程序在malloc()
期间接收到信号后将堆栈内容写入文件。为此,我尝试使用backtrace()
和backtrace_symbols_fd()
函数,但后来发现它们不是异步信号安全的。我写了下面的代码只是为了测试,看起来程序在大多数运行中都挂起了。
#include <execinfo.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
typedef int bool;
#define true 1
#define false 0
static void signal_handler_child(int sig)
{
char error_msg_buffer[4096];
int fd = open("./backtrace_log.txt", O_RDWR | O_TRUNC | O_CREAT, 0777);
strcpy(error_msg_buffer, "entered signal_handler_child()");
write(fd, error_msg_buffer, strlen(error_msg_buffer));
void* buffer[1024];
const int size = backtrace(buffer, 1024);
if(size <= 0)
{
strcpy(error_msg_buffer, "unable to dump call stack trace: backtrace() returned bad size");
write(fd, error_msg_buffer, strlen(error_msg_buffer));
return ;
}
backtrace_symbols_fd(buffer, size, fd);
close(fd);
_exit(EXIT_SUCCESS);
}
int main(int argc, char *argv[])
{
pid_t pid = fork();
if(pid == 0)
{
signal(SIGSEGV, signal_handler_child);
while(true)
{
void *pointer = malloc(1000000);
free(pointer);
}
}
else if(pid == -1)
{
printf("fork() error\n");
}
else
{
sleep(3);
if(kill(pid, SIGSEGV) == -1)
printf("kill() error\n");
wait(NULL);
}
}
那么,在这种情况下,如何安全地将堆栈内容写入文件?一般情况下
backtrace()
可以使用下面的malloc()
吗?还有人说
backtrace_symbols_fd()不调用malloc(3),因此可以使用
在后一个函数可能失败的情况下。
但如果
backtrace_symbols_fd()
实际上受到backtrace()
的影响,那么函数malloc()
的意义何在?我是新来的LinuxAPI,所以任何帮助都是值得感谢的。
最佳答案
backtrace
调用malloc
的主要原因是它需要使用libgcc_s
加载dlopen
。通过首先调用backtrace
来初始化自身,可以获得一些额外的可靠性。对backtrace
的后续调用不应触发对malloc
的调用,如下例所示。
#define _GNU_SOURCE
#include <dlfcn.h>
#include <execinfo.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
void *
malloc (size_t size)
{
const char *message = "malloc called\n";
write (STDOUT_FILENO, message, strlen (message));
void *next = dlsym (RTLD_NEXT, "malloc");
return ((__typeof__ (malloc) *) next) (size);
}
int
main (void)
{
/* This calls malloc. */
puts ("First call to backtrace.");
void *buffer[10];
backtrace (buffer, 10);
/* This does not. */
puts ("Second call to backtrace.");
backtrace (buffer, 10);
}
出于其他原因,libgcc unwinder仍然不是异步信号安全的,但是glibc假设它是(对于线程取消之类的事情),并且它通常工作得好像是异步信号安全的。
关于c - 在malloc期间接收信号,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46863569/