malloc()如何导致SIGSEGV?

malloc()如何导致SIGSEGV?,c,gdb,malloc,segmentation-fault,C,Gdb,Malloc,Segmentation Fault,我的程序中有一个奇怪的bug,在我看来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->m

我的程序中有一个奇怪的bug,在我看来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\u entry\u s**)malloc(SIMCLIST\u MAX\u SPARE\u 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
可能会出错,例如当堆损坏时。请检查您写入的内容是否超出了以前任何分配的范围。

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


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

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


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

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

这意味着:

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

#2:编写一个单元测试来调用这部分代码

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


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

malloc()
(以及
realloc()
calloc()
)触发核心转储的方法有很多种。这些方法包括:

  • 缓冲区溢出:超出分配空间的结尾写入(践踏
    malloc()
    保存在那里的控制信息)
  • 缓冲区下溢:在分配的空间开始之前写入(践踏
    malloc()
    保存在那里的控制信息)
  • 释放未被代码> > MARROCK()/代码>分配的内存。在混合C和C++程序中,这将包括释放由C++分配的内存,由<代码>新< /代码> .
  • 释放部分指向由
    malloc()
    分配的内存块的指针-这是前一种情况的特殊情况
  • 释放已释放的指针-臭名昭著的“双重释放”

使用诊断版本的
malloc()
或在系统的标准版本中启用诊断,可能有助于识别其中的一些问题。例如,它可能能够检测小的下溢和溢出(因为它分配了额外的空间,以便在您请求的空间周围提供缓冲区),它可能会检测到释放未分配或已释放内存的尝试,或通过分配的空间释放指针的尝试,因为它将与分配的空间分开存储信息。代价是调试版本占用更多空间。一个真正优秀的分配器将能够记录堆栈跟踪和行号来告诉您代码中的分配发生在何处,或者第一次空闲发生在何处。

代码有问题。如果malloc返回NULL,则说明代码中未正确处理此情况。您只需假设内存已分配给您,而实际上尚未分配。这可能会导致内存损坏。

te,不建议多次调用
srandom()
。为了避免将来出现错误,即使在
list\u init()
中也只调用一次,您应该将种子设定移动到更明显执行一次的位置,例如靠近
main()的顶部
。使用valgrind!其他海报也提到了这个工具,但遗憾的是没有得到太多的支持票。这个答案没有错,但任何关于内存损坏的讨论都是不完整的,如果没有使用valgrind的警告!我打电话给free()时收到了一个sigsegv.我在valgrind下运行了代码,它表明我编写的代码超出了缓冲区,并损坏了堆。