2009-09-17 15 views
8

私のプログラムには奇妙なバグがあります。malloc()がSIGSEGVを引き起こしているように見えます。私の理解が行き届かない限り、それは意味をなさないものです。私は動的リストのためにsimclistというライブラリを使用しています。ここで malloc()はどのようにSIGSEGVを引き起こしますか?

は後に参照される構造体である:

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がt oスタックトレース。私はデバッグに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 

すべてのヘルプや洞察力が非常に高く評価されています

これは、スタックトレースです!

+0

'list_t'はどのように宣言されていますか? –

+0

補足として、 'srandom()'を複数回呼び出すことはお勧めしません。 'list_init()'でさえ未来のバグを避けるためには、一度しか呼び出されないことが知られています。例えば、 'main()'の一番上など、一度明示的に実行される場所にシーディングを移動する必要があります。 – RBerteig

答えて

25

mallocたとえば、ヒープが破損しているときにsegfaultを実行できます。以前の割り当ての範囲を超えて何も書いていないことを確認してください。

+20

そしてvalgrindを使用してください!他のポスターはこのツールについて言及していましたが、悲しいことに多くのアップフォースを得ていませんでした。この回答は間違っていませんが、valgrindを使用するよう勧めることなしにメモリ破損の議論は不完全です! –

+2

私はfree()を呼び出すときにsigsegvを取得していました。私はvalgrindの下でコードを実行し、バッファーを超えて書いてヒープを破損していることを示しました。 –

12

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

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

16

おそらく、コードの他の部分でメモリ違反が発生している可能性があります。 Linuxを使用している場合は、間違いなくvalgrindを試す必要があります。私はvalgrindを通過しない限り、私自身のCプログラムを信頼することはありません。

EDIT:もう1つの有用なツールはElectric fenceです。 Glibcは、メモリの問題をデバッグするために、環境変数MALLOC_CHECK_も提供しています。これらの2つの方法は、バンググラインドほどのランニングスピードには影響しません。

1

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

これが意味:

#1:GDBが情報をナンバリング正しい行を取得することを確認するために、-O0でコードをコンパイルします。

#2:コードのこの部分を呼び出す単体テストを書く。

私の推測では、コードを別々に使用すると正しく動作するということです。バグの原因が分かるまで、同じ方法で他のモジュールをテストすることができます。

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

4

malloc()(およびrealloc()およびcalloc())からのコアダンプをトリガする方法が多数あります。

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

malloc()の診断バージョンを使用するか、システムの標準バージョンで診断を有効にすると、これらの問題のいくつかを特定するのに役立ちます。たとえば、小さなアンダーフローとオーバーフローを検出することができます(要求されたスペースの周りにバッファ領域を確保するために余分な領域を割り当てるため)。おそらく、割り当てられていないメモリまたは解放されたメモリを解放しようとする試みを検出できますポインタは割り振られたスペースを部分的に経由します。割り当てられたスペースとは別に情報を格納するためです。デバッグ用のバージョンでは、より多くのスペースが必要です。本当に良いアロケータは、スタックトレースと行番号を記録して、コード内のどこで割り振りが発生したのか、最初のフリーが発生した場所を知ることができます。

0

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

関連する問題