malloc()如何导致SIGSEGV?

我的程序中有一个奇怪的错误,在我看来malloc()正在引起一个SIGSEGV,据我所知,这没有任何意义。 我正在使用一个名为simclist的库来创建动态列表。

这是一个稍后引用的结构:

typedef struct { int msgid; int status; void* udata; list_t queue; } msg_t; 

这是代码:

 msg_t* msg = (msg_t*) malloc( sizeof( msg_t ) ); msg->msgid = msgid; msg->status = MSG_STAT_NEW; msg->udata = udata; list_init( &msg->queue ); 

list_init是程序失败的地方,这里是list_init的代码:

 /* list initialization */ int list_init(list_t *restrict l) { if (l == NULL) return -1; srandom((unsigned long)time(NULL)); l->numels = 0; /* head/tail sentinels and mid pointer */ l->head_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); l->tail_sentinel = (struct list_entry_s *)malloc(sizeof(struct list_entry_s)); l->head_sentinel->next = l->tail_sentinel; l->tail_sentinel->prev = l->head_sentinel; l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL; l->head_sentinel->data = l->tail_sentinel->data = NULL; /* iteration attributes */ l->iter_active = 0; l->iter_pos = 0; l->iter_curentry = NULL; /* free-list attributes */ l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct list_entry_s *)); l->spareelsnum = 0; #ifdef SIMCLIST_WITH_THREADS l->threadcount = 0; #endif list_attributes_setdefaults(l); assert(list_repOk(l)); assert(list_attrOk(l)); return 0; } 

l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS *行 – l->spareels = (struct list_entry_s **)malloc(SIMCLIST_MAX_SPARE_ELEMS *是根据堆栈跟踪引起SIGSEGV的地方。我使用gdb / nemiver进行调试但是不知所措。第一次调用此函数它工作正常,但它总是第二次失败.malloc()如何导致SIGSEGV?

这是堆栈跟踪:

 #0 ?? () at :0 #1 malloc () at :0 #2 list_init (l=0x104f290) at src/simclist.c:205 #3 msg_new (msg_switch=0x1050dc0, msgid=8, udata=0x0) at src/msg_switch.c:218 #4 exread (sockfd=8, conn_info=0x104e0e0) at src/zimr-proxy/main.c:504 #5 zfd_select (tv_sec=0) at src/zfildes.c:124 #6 main (argc=3, argv=0x7fffcabe44f8) at src/zimr-proxy/main.c:210 

非常感谢任何帮助或见解!

例如,当堆损坏时, malloc可以进行段错误。 检查您是否正在编写超出先前分配范围的任何内容。

可能在代码的其他部分发生内存冲突。 如果你在Linux上,你一定要试试valgrind。 我永远不会相信自己的C程序,除非它通过valgrind。

编辑:另一个有用的工具是电围栏 。 Glibc还提供MALLOC_CHECK_环境变量来帮助调试内存问题。 这两种方法不像valgrind那样影响运行速度。

您可能在此调用之前通过缓冲区溢出或使用未由malloc分配的指针(或已经释放)调用free来损坏您的堆。

如果malloc使用的内部数据结构以这种方式被破坏,则malloc使用无效数据并可能崩溃。

有许多方法可以从malloc() (以及realloc()calloc() )触发核心转储。 这些包括:

  • 缓冲区溢出:写入超出分配空间的末尾(践踏malloc()保存的控制信息)。
  • 缓冲区下溢:在分配的空间开始之前写入(践踏malloc()控制信息)。
  • 释放未由malloc()分配的malloc() 。 在混合的C和C ++程序中,这将包括释放用C ++分配的内存。
  • 释放指向malloc()分配的内存块的指针 – 这是前一种情况的特例。
  • 释放已经释放的指针 – 臭名昭着的’双重免费’。

在系统的标准版本中使用malloc()的诊断版本或启用诊断可能有助于识别其中一些问题。 例如,它可能能够检测到小的下溢和溢出(因为它分配了额外的空间以在您请求的空间周围提供缓冲区),并且它可能检测到释放未分配或已释放的内存的尝试或指针分配空间的一部分 – 因为它将与分配的空间分开存储信息。 成本是调试版本占用更多空间。 一个非常好的分配器将能够记录堆栈跟踪和行号,以告诉您代码中的分配位置,或第一次自由发生的位置。

您应该尝试单独调试此代码,以查看问题是否实际位于生成segfault的位置。 (我怀疑它不是)。

这意味着:

#1:使用-O0编译代码,以确保gdb获得正确的行编号信息。

#2:编写一个unit testing,调用这部分代码。

我的猜测是,单独使用时代码可以正常工作。 然后,您可以以相同的方式测试其他模块,直到找出导致错误的原因。

正如其他人所建议的那样,使用Valgrind也是一个非常好的主意。

代码有问题。 如果malloc返回NULL,则在您的代码中无法正确处理此情况。 你只是假设已经为你分配了实际上没有的内存。 这可能会导致内存损坏。