9

プログラムに奇妙なバグがあります。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 *は、スタック トレースによると、SIGSEGV が発生する場所です。デバッグに gdb/nemiver を使用していますが、途方に暮れています。この関数が最初に呼び出されたときは正常に機能しますが、2 回目は常に失敗します。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

どんな助けや洞察も大歓迎です!

4

6 に答える 6

27

mallocたとえば、ヒープが破損している場合にセグメンテーション違反を起こすことができます。以前の割り当ての境界を超えて何かを書いていないことを確認してください。

于 2009-09-17T20:07:06.610 に答える
17

おそらく、コードの他の部分でメモリ違反が発生しています。Linux を使用している場合は、必ず valgrind を試してください。valgrind に合格しない限り、私は自分の C プログラムを決して信用しません。

編集: 別の便利なツールは電気柵です。glibc は、メモリの問題をデバッグするのに役立つMALLOC_CHECK_環境変数も提供します。これら 2 つの方法は、valgrind ほど実行速度に影響しません。

于 2009-09-17T20:10:32.857 に答える
12

おそらく、この呼び出しの前に、バッファ オーバーフローや、割り当てられていない(または既に解放された)freeポインタを使用して呼び出すことにより、ヒープのどこかが破損している可能性があります。malloc

malloc が使用する内部データ構造がこのように破損した場合、malloc は無効なデータを使用しており、クラッシュする可能性があります。

于 2009-09-17T20:07:34.953 に答える
4

malloc()(およびrealloc()および)からコアダンプをトリガーする方法は無数にありますcalloc()。これらには以下が含まれます:

  • バッファオーバーフロー:割り当てられたスペースの終わりを超えて書き込みます(malloc()そこに保持されていた制御情報を踏みにじる)。
  • バッファアンダーフロー:割り当てられたスペースの開始前に書き込みます(そこに保持されていた制御情報を踏みにじりますmalloc())。
  • によって割り当てられなかったメモリを解放しますmalloc()。CとC++が混在するプログラムでは、によってC++に割り当てられたメモリを解放することが含まれnewます。
  • -によって割り当てられたメモリブロックの途中を指すポインタを解放しますmalloc()。これは、前のケースの特殊なケースです。
  • すでに解放されたポインタを解放する-悪名高い「ダブルフリー」。

システムの標準バージョンの診断バージョンを使用するmalloc()か、診断を有効にすると、これらの問題のいくつかを特定するのに役立つ場合があります。たとえば、小さなアンダーフローとオーバーフローを検出できる場合があり(要求したスペースの周囲にバッファゾーンを提供するために追加のスペースが割り当てられるため)、割り当てられていない、またはすでに解放されているメモリを解放しようとする試みを検出できる可能性があります。または、割り当てられたスペースの途中にあるポインター-割り当てられたスペースとは別に情報を格納するためです。コストは、デバッグバージョンがより多くのスペースを必要とすることです。本当に優れたアロケータは、スタックトレースと行番号を記録して、コード内で割り当てが発生した場所、または最初の空きが発生した場所を示すことができます。

于 2009-09-17T20:19:25.400 に答える
2

このコードを個別にデバッグして、問題が実際にsegfaultが生成された場所にあるかどうかを確認する必要があります。(そうではないと思います)。

これの意味は:

#1:コードを-O0でコンパイルして、gdbが正しい行番号情報を取得することを確認します。

#2:コードのこの部分を呼び出す単体テストを記述します。

私の推測では、コードは個別に使用すると正しく機能します。その後、バグの原因がわかるまで、同じ方法で他のモジュールをテストできます。

他の人が示唆しているように、Valgrindを使用することも非常に良い考えです。

于 2009-09-17T20:17:53.280 に答える
0

コードに問題があります。mallocがNULLを返す場合、このケースはコードで正しく処理されません。実際にはメモリが割り当てられていないのに、メモリが割り当てられていると単純に想定します。これにより、メモリが破損する可能性があります。

于 2009-09-27T09:12:29.377 に答える