2012-03-01 11 views
6

編集: コメント者の助けを借りてわかりました。私のタイトルで提起された質問に答えるには:いいえ、スタックの破損ではなく、gdbが間違った値を報告しています。プログラムは実際には期待通りに動作し、正しいポインタthisを持っています。 この質問を投稿するように促す実際のバグの振る舞いは、私がここで説明する問題とはまったく無関係です。コンストラクターが間違った "this"ポインターで呼び出されました。このスタックの破損ですか?

最初に警告が表示されます。私はこれがメモリー破損の問題だと思っています。通常、「コードを徹底的にチェックしてください」以外の答えは期待できませんが、この現象が繰り返し現れるのを見て、あなたの一部が洞察を得て、そのソースを見つけることができます。

私は現在、Cプログラムの変数の可能な範囲を追跡する間隔の静的解析を実装しています。私の基本区間クラスのコピーコンストラクタは次のようになります。

itvt::itvt(const itvt& i) 
    : _i(i.type == INTBV ? new intbv_intervalt(i.i()) : NULL), 
    _f(i.type == FLOAT ? new float_intervalt(i.f()) : NULL), 
    type(i.type), other_bottom(i.other_bottom) 
{ } 

を今、私はメモリ破壊のバグを発見し、次のコードスニペットにそれを追跡するために管理:

itvt itvt::get_split(bool le) const 
{ 
    itvt result(*this); 
    [...] 
} 

は、GDBを使用して、Iコンストラクタの呼び出しが「結果」オブジェクト構築するようでいないことが判明:

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) n 
519 if(is_singleton() || is_bot()) 
(gdb) print result 
$3 = { 
    _i = { 
    _M_ptr = 0x7fff5fbfe100 
    }, 
    _f = { 
    _M_ptr = 0x7fff5fbfed60 
    }, 
    type = 1606410016, 
    other_bottom = 255 
} 
(gdb) print *this 
$4 = { 
    _i = { 
    _M_ptr = 0x1020833a0 
    }, 
    _f = { 
    _M_ptr = 0x0 
    }, 
    type = itvt::INTBV, 
    other_bottom = false 
} 

が深い探している、私は間違ったオブジェクトにコピーコンストラクタの内部、「この」ポインタのポイントを見つけること

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) print &result 
$5 = (itvt *) 0x7fff5fbfdee0 
(gdb) s  
itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
500  type(i.type), other_bottom(i.other_bottom) 
(gdb) print this 
$6 = (itvt * const) 0x7fff5fbfdf80 

「結果が」アドレス0x7fff5fbfdee0でスタックに割り当てられているので、私はコピーコンストラクタ内の「この」ポインタが同じアドレスを指すように期待します。代わりに0x7fff5fbfdf80を指します。

コピーコンストラクタが何かを初期化しているようですが、呼び出されるスタック上の "result"オブジェクトは初期化されていません。実際に、私はコンストラクタは完全によく初期化することをメモリ位置にアクセスすることができます。

Breakpoint 1, itvt::get_split (this=0x1016af560, le=false) at itv.cpp:517 
517 itvt result(*this); 
(gdb) s  
itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
500  type(i.type), other_bottom(i.other_bottom) 
(gdb) finish 
Run till exit from #0 itvt::itvt (this=0x7fff5fbfdf80, [email protected]) at itv.cpp:500 
itvt::get_split (this=0x1016af560, le=false) at itv.cpp:519 
519 if(is_singleton() || is_bot()) 
(gdb) print *((const itvt*) (0x7fff5fbfdf80)) 
$7 = { 
    _i = { 
    _M_ptr = 0x1016b6d10 
    }, 
    _f = { 
    _M_ptr = 0x0 
    }, 
    type = itvt::INTBV, 
    other_bottom = false 
} 

私の最初の質問:でき間違ったオブジェクトへの「this」ポインタのポイントが通常の動作として説明するということ?それはいくつかの奇妙なメモリ破損の問題のようだが、多分私は何かが不足している。

私はg ++と "-O0 -ggdb"フラグでコンパイルしており、すべてのbtwを新しく再コンパイルしました。ここに私のG ++バージョンです:

[email protected] ai$ g++ --version 
i686-apple-darwin11-llvm-g++-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00) 
Copyright (C) 2007 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

私の2番目の質問:それはメモリの破損がある場合、あなたは私が原因を追跡できる方法上の任意のアドバイスを持っています。私は通常、gdbを使って根本的な問題にこのような問題を抱えていますが、私は今どこを見るべきか分かりません。

この現象は初めて発生しました。私はそれが他の人のバグを調べるときに起こるのを見ました。私は実際に直接直接それに対処することは決してなかった、それはちょうど起こって停止したまたは少なくともいくつかの他のコードの変更後に目に見える問題である。これは、おそらくgdbを使ってスタックを見ているだけの奇妙な人工物であると信じています。

あなたが提供できるアドバイスや洞察に感謝します。

編集:ここでは があるitvtクラスの関連するスニペットです:

class itvt 
{ 
protected: 
    typedef std::auto_ptr<intbv_intervalt> iptrt; 
    typedef std::auto_ptr<float_intervalt> fptrt; 
    iptrt _i; 
    fptrt _f; 
public: 
    typedef enum {INTBV, FLOAT, OTHER} itv_typet; 
    itv_typet type; 

    bool other_bottom; 

    //copy constr 
    itvt(const itvt& i); 

    inline intbv_intervalt& i() { return *_i; } 
    inline float_intervalt& f() { return *_f; } 
    inline const intbv_intervalt& i() const { return *_i; } 
    inline const float_intervalt& f() const { return *_f; } 

    itvt get_split(bool le) const; 

    [...] 
}; 
+0

情報をいただきありがとうございます。それは別の文脈で私にとって興味深いものです。いいえ、itvtクラスは完全に退屈/非仮想です。 itvtやそのメンバーには、仮想性や継承はありません。 – leo

+1

ちょうど質問です: 'gdb'のあなたのバージョンは最新です。最近のバージョンのコンパイラで 'gdb'の古いバージョンを使用すると' gdb'が間違ったものを表示するケースがあります。 (先験的に、これはメジャーバージョンを変更するときにのみ問題になるはずです:g ++ 4.0.0が最初に出てきたら、gdbはしばらく時間がかかりましたが、あなたは決して知りません)。 –

+2

2番目の点は、 '関数に入るために、いくつかのデバッガ(私はgdbについてはわかりませんが、VSでこれを見たことがあります)は、ローカルスタックフレームを設定するための関数に十分には行きません。これにより、すべての値が不正確になります(デバッガから見た場合)。 –

答えて

4

2番目の質問:valgrindを使用し、それはあなたがここで必要なものは本当にです。それは、すべての割り当て/無料を追跡し、解放されたメモリだけでなく、他の多くのものを試して使用するかどうかを指示します。メモリの破損が表示されます。

2

コメント者の助けを借りて私はそれを理解しました。gdbが真実を伝えていないようです(古いgdbバージョンの可能性があります)。プログラムは実際には期待通りに動作します。

問題を調べるように促す実際のバグの動作は、オブジェクトの初期化とはまったく関係ありませんでした。

関連する問題