2009-07-31 8 views
1

私はC++コードを持っています。私はそれをコンパイルするためにMSC9を使います。 ランダムにクラッシュし続けます。例えば、 ``を使ってPerlから呼び出された場合、クラッシュしますが、コマンドラインやUltimate ++から呼び出されたときにクラッシュすることはありません。C++の機能を終了するときにプログラムがクラッシュする...それはどう思いますか?

私はそれをperlから呼び出すことを意味します。 f.exe arg1 arg2 arg3

スタックトレースはあまり表示されません。それは、ラインによってプログラムラインが...

を返すときにプログラムが終了時に失敗したことを証明したので、それはその

int funcname() 
{ 
    return 0; <-- crashing after that... 
} 

のようである私は、スタックが破損していると思いますし、スタックした後に巻き戻されるトレースクラッシュ..

何が原因なのですか? プログラムはpcre、stl、iteratorsを使用します。イテレータがスタックを破壊することはできますか? このようなエラーをどのようにキャッチしますか?

コンパイラのバグはありますか?

注:デバッグバージョンクラッシュしていない、唯一のリリースバージョン...

バグは、このP-VECTORクラスに関連しているようです。

struct complexstr 
{ 
pvector<int> v; 
string v2; 
hash_map<string> hm; 
vector<string> vs; // similar 
int i; 
}; 

この行ので失敗するようだ:

私はこれに似た構造体を持っている

complexstr s1; 
complexstr s2; 

s2=s1; // it seems to fail here, if this is not there... there is no error. 

私はこの問題は、以下のクラス... STDであると思います::コピーはpvector operator =(const pvector & pv)で正しいですか?

pvectorはperl互換性のあるベクトルです...そのインデックスは、ベクトルの割り当てられたサイズより大きくすることができます。

更新1: 割り当てにリークがあるとの提案がありました。 私はそれが今どのように見えるかで割り当て... 変更:

pvector& operator=(const pvector &pv) 
    { 
    delete [] m_rgArray; 
    m_rgArray=new value_type[pv.allocated]; 
    m_nIndex=pv.m_nIndex; 
    allocated=pv.allocated; 
    std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray); 
    return *this; 
    } 

注:戻り値の型に&を追加することにより、クラッシュがまだ残っていました。 しかし、リークを削除した後、delete [] m_rgArray;を追加してください。 、 プログラムはもうクラッシュしません。分かりません。私が漏れを知っている限り、 はクラッシュしません。だから問題は解決されたようです(?)。疑問符は私の驚きを示しています。 Update2: いいえ、問題は戻ってきました。それはちょっと消えてしまった。 Update3:私はそれを見つけたと思う。正確な場所を見つけるために、gflags.exeとwindbg.exeというMicrosoftのデバッグツールからユーティリティを使用しました。 gflags.exe/p/myprog.exe/fullを有効にしてヒープバグの例外を有効にしました。 現時点では、バグはFindClose(ハンドル)によって発生していると思います。ハンドルは初期値ではなくランダム値でした。

旧バージョン:

template<class _Ty> 
    class pvector 
    { 
    public: 
    _Ty * m_rgArray; // Declare array 
    int m_nIndex; // Index to array 
    int allocated; 
    _Ty undefvalue; 
    typedef _Ty value_type; 
    typedef value_type & reference; 
    typedef const value_type & const_reference; 
    typedef custom_iterator<_Ty> iterator; 
    typedef custom_iterator<_Ty> const_iterator; 
    typedef int difference_type; 
    typedef int size_type; 
    //typedef typename pvector_type_traits<_Ty>::default_value default_value; 

    pvector() : m_nIndex(0) 
    { // init index to 0 
     m_rgArray = new value_type[10]; 
     allocated = 10; 
     fill(0); 
    } 

    pvector(size_type s) : m_nIndex(0) 
    { // init index to 0 
     size_type defsize = 10; 
     if (s>10) 
     { 
     defsize = s; 
     } 
     m_rgArray = new value_type[defsize]; 
     allocated = defsize; 
     fill(0); 
    } 
     pvector(pvector const& pv) 
    : m_rgArray(new value_type[pv.allocated]), 
    m_nIndex(pv.m_nIndex),allocated(pv.allocated) 
    { 
    std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray);  
    } 

    pvector operator=(const pvector &pv) 
    { 
    m_rgArray=new value_type[pv.allocated]; 
    m_nIndex=pv.m_nIndex; 
    allocated=pv.allocated; 
    std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray); 
    return *this; 
    } 
    void clear() 
    { 
     m_nIndex=0; 
     fill(allocated);  
    } 

    ~pvector() { 
    delete []m_rgArray; 
    } 

    size_type size() const 
    { // return length of sequence 
     return m_nIndex; 
    } 

    size_type max_size() const 
    { // return maximum possible length of sequence 
     return 0; 
    } 

    void fill(size_type si) 
    { 
     for (size_type i = si;i<allocated;i ++) 
     { 
     m_rgArray[i] = pvector_type_traits<_Ty>::default_value(); 
     } 
    } 

    bool empty() const 
    { // test if sequence is empty 
     return (m_nIndex > 0 ? false : true); 
    } 

    iterator begin() 
    { // return iterator for beginning of mutable sequence 
     return iterator(&m_rgArray[0]); 
    } 

    const_iterator begin() const 
    { 
     return const_iterator(&m_rgArray[0]); 
    } 

    iterator end() 
    { // return iterator for end of mutable sequence 
     return iterator(&m_rgArray[m_nIndex]); 
    } 

    const_iterator end() const 
    { 
     return const_iterator(&m_rgArray[m_nIndex]); 
    } 
    reference operator[](size_type i) 
    { 
     if (m_nIndex>i) 
     { 
     return m_rgArray[i]; 
     } 
     else if (i >= allocated) 
     { 
      resize(i * 2); 
     } 
     m_nIndex = i + 1; 
     return m_rgArray[i]; 
    } 
    void resize(size_type s) 
    { 
     value_type * m_rgArray2; 
     size_type old_allocated = allocated; 
     allocated = s; 
     m_rgArray2 = new value_type[allocated]; 
     //if (allocated>m_nIndex) 
     //{ 
     // m_nIndex=allocated; 
     // } 
     // cout <<"m_nIndex" << m_nIndex << "allocated" << allocated << endl; 
     if (m_nIndex>allocated) 
     { 
     m_nIndex=allocated; 
     } 
     for (size_type i = 0;i<m_nIndex;i ++) 
     { 
     m_rgArray2[i] = m_rgArray[i]; 
     } 
     delete []m_rgArray; 
     m_rgArray = m_rgArray2; 
     fill(old_allocated); 
    } 

    reference back() 
    { 
     return &m_rgArray[m_nIndex - 1]; 
    } 

    const_reference back() const 
    { 
     return m_rgArray[m_nIndex - 1]; 
    } 

    void push_back(const _Ty &_Val) 
    { // insert element at end 
     if (size() < allocated) 
     m_rgArray[m_nIndex ++ ] = _Val; 
     else 
     { 
     resize(allocated * 2); 
     m_rgArray[m_nIndex ++ ] = _Val; 
     } 
    } 

    }; 
+4

もちろん、それはコンパイラのバグです! :) 関数のコードを投稿すると役に立ちます。 – Indy9000

+2

それは何でもかまいません。いくつかのコードを表示します。このようなエラーをキャッチする最も速いqayは通常、コードを非常に慎重に調べることです。 – nos

+0

ここにいくつかのコードがあります – Aftershock

答えて

12

それは、スタックを破壊バッファオーバーランすることができます。関数を実行している間にローカルに定義されたバッファの外側に書き込むと、戻りアドレスを上書きすることができ、関数から戻るとプログラムがクラッシュする可能性があります。

ローカル(スタックに割り当てられた)変数のアドレスで動作するステートメントを探してください。バッファオーバーランが問題の原因になっている可能性があります。私は考えることができる

3

可能性:

  • 異なるイテレータ/ STLプロジェクトと何でもそれがにリンクされて間のデバッグ設定を確認します。 Debug Iterator SupportおよびChecked Iteratorを参照してください。
  • プロジェクトとそれがリンクされているものとのCRT設定が異なります。不一致を確認するにはDependency Walkerを使用してください。
  • 関数内の不正なコード、たとえば配列や文字列の末尾からの書き込みなどのためにスタックが破損しています。
  • スタックまたは変数の破損を引き起こすマルチスレッドの問題。
  • (あなたはPerlのからそれを呼び出すに述べたように)(funcnameに)あなたの関数内
+0

私はスタックに配列を割り当てません、私はどこでもベクトルstlクラスを使用すると思います。 – Aftershock

+0

それはそれが配列のオーバーランになることはできませんので、それはできますか? – Aftershock

+0

なぜですか?私はコマンドラインツールとしてPerlから呼び出しています。そこに通話規約はどこにありますか?コマンドライン引数だけがあります。 – Aftershock

0

呼び出し規約に不一致またはfuncnameにによって呼び出された機能の一つに、あなたは、スタックが破損いくつかのコードを持っているかもしれません。

割り当てられたターゲットバッファがコピーするデータのサイズに合わない場合、メモリコピーまたは文字列コピーが発生します(sizeofと要素数を使用したサイズの計算ミス、文字列のコピーのためにターゲットバッファのサイズを変更するときに、文字列の最後のターミネータ)。

ローカル変数または配列を参照してそのポインタを介してポインタを変更するときに、ポインタのアルティメットが遭遇する可能性はそれほどありません。

2

デストラクタではないスタックベースのオブジェクトはありますか?デバッガによっては、デバッガがいつ実行されているかを知るのが難しい場合があります。それは、他のコメントで言及されたすべてに加えて、それに関連するものかもしれません。

1

私は次の関数は、それまでより多くのコード

int funcname() 
{ 
    return 0; <-- crashing after that... 
} 

機能のリターンを持っていると仮定している、任意のスタック変数は、そのデストラクタが呼ばれています。デストラクタの1人でクラッシュが発生している可能性があります。それを追跡する方法

は、関数内で宣言された変数のデストラクタにブレークポイントを置きます。各デストラクタをステップ実行します。デストラクタが呼び出されると、ベースクラスのデストラクタのチェーンが自動的に呼び出され、それらのいずれかに破損が存在する可能性があることに注意してください。

0

あなたの詳細はクラッシュに固有のものではないので、IDEを使用してアプリケーションをデバッグすることをお勧めします。 ProjectProperties-> ConfigurationProperties-> Debugでperl/ultimate ++アプリケーションとしてコマンドとコマンドの引数を設定します。デバッグモードでコンパイルし、クラッシュが疑われる場所にブレークポイントを設定します。問題を突き止めて、クラッシュ自体に意味のあるメッセージを出すのはかなり簡単です。

+0

注:Perlから呼び出されたときにのみ、Ultimate ++ Ideでクラッシュしませんでした。 – Aftershock

+0

何が間違っているのか分かりません - 私はちょうどアプリケーションをデバッグする方法について述べました。 1つのインスタンスでは動作するので、入力パラメータが期待どおりではないと思われます。 –

0

あなたの代入演算子は、参照を返すべきである:

pvector& operator=(const pvector &pv) { 

私はそれが問題になるが、それに打撃を与えることはないだろう。

+0

私はそれを変えました、それは問題を解決しませんでした。 – Aftershock

0

デバッガとは何ですか?リターンラインの後では、オブジェクトはスコープから外れるすべてのデストラクタを通過し、そのうちの1つがほぼ確実にねじれています。 復帰線にブレークポイントを置き、クラッシュするまでデバッガをステップスルーします。

0

私の推測では、サイズ変更中にpvectorが配列をオーバーランさせることにいくつかの問題があります。私はそれが本当であるかどうかを見つけるためにコードを読むことを試みているが、私は何も明白ではない。あなたが本当に望むのは、アクセスされたインデックスに合うように成長するベクトルであれば、あなた自身で全体を書く必要はありません。 std :: vectorを代わりに拡張し、単にreserve()/ resize()メソッドを使用し、STLにすべてのコピーとメモリの管理とイテレータを処理させることができます。以下の作業をする必要があります:

template<typename StoredType> 
class pvector : public std::vector<StoredType> 
{ 
public: 
    typedef typename std::vector<StoredType, std::allocator<StoredType> >::reference reference; 
    typedef typename std::vector<StoredType, std::allocator<StoredType> >::size_type size_type; 

    reference at(size_type n) 
    { 
     size_type need = n+1; 
     if(need > std::vector<StoredType>::capacity()) 
     { 
      std::vector<StoredType>::reserve(need * 2); 
      std::vector<StoredType>::resize(need); 
     } 
     else if(need > std::vector<StoredType>::size()) 
     { 
      std::vector<StoredType>::resize(need); 
     } 
     return std::vector<StoredType>::at(n); 
    } 

    reference operator[](size_type n) 
    { 
     return at(n); 
    } 
}; 

を、私はLinux上でGCC 4.1.2とそれをテストし、うまくいけば、それはあまりにもWindows上でコンパイルします。

編集:それは良いアイデアではない(私は何か新しいことを学んだ)と思うので、継承しない新しいバージョンがあります。あなたが欲しいメソッドの残りの部分を実装し、ちょうどパススルーm_vectorにすることができます。このコードで間違ったくさんあります

template<typename StoredType> 
class pvector 
{ 
public: 
    typedef StoredType& reference; 
    typedef int size_type; 

    reference at(size_type n) 
    { 
     int need = n+1; 
     if(need >= m_vector.capacity()) 
     { 
      m_vector.reserve(need * 2); 
      m_vector.resize(need); 
     } 
     else if(need >= m_vector.size()) 
     { 
      m_vector.resize(need); 
     } 
     return m_vector.at(n); 
    } 

    reference operator[](size_type n) 
    { 
     return at(n); 
    } 

    size_type capacity() { return m_vector.capacity(); } 
    size_type size() { return m_vector.size(); } 

private: 
    std::vector<StoredType> m_vector; 
}; 
+0

stlがそれを継承/拡張するために十分に書かれていないところを読んでいるので、私はこれをしませんでした – Aftershock

+0

うーん... "仮想デストラクタ"の問題を指摘していると思います。 STLから継承することが悪い理由がわかるのは、それが私が見つけることができる唯一のものです。もしあなたがそれを心配しているならば、クラスをそのクラスから継承するのではなく、そのクラスの中にベクトルを含めることによって上記を実装することができます。ベクタがすでに行っていることをすべて書き直すことは、私にとっては労力の無駄だと思われます。 – CodeGoat

+0

また、正常なベクトル(多型を持たない)を取るようなものに上記のクラスを渡そうとしない限り、あなたは大丈夫でしょう。 – CodeGoat

3

  • 命名は - 私はすでにに問題があることを指摘しました_Tyですが、なぜ一部のメンバーはm_などで始まらないのですか?いくつかのローカル変数もm_で始まります。良くない。

  • 割り当てopは、すでに指摘したように参照を返しません。

  • 割り当てopには最初にメモリリークがあります。最初の行に、既にコンテンツがあるm_rgArrayに割り当てられます。これらはリークします。

これは初心者向けです。これらのどれもがクラッシュを引き起こすべきではありませんが、彼らはすべて修正が必要です。すべての問題を修正するために、私はもう一度やり直して、一度に1つの関数を書くだけでなく、それをテストします。テストを実行し、それが機能する場合は、次の関数、次のテストなどを記述します。このようなテンプレートクラスに多くの努力を払うことは価値があります。なぜなら、それらが正しいとすれば、それらは非常に便利ですが、間違って連続的な痛みの原因になるからです。

+2

これらのテストを書く際には、大きな3つのテストを必ず実行してください。あなたが割り当て、コピーの作成と破壊を適切に処理し、必要なすべてのdtorsが呼び出され、何もリークされない、またはダブル・ダンプされないことをテストします。 – jalf

1

あなたは私はあなたが漏れていると思う同じ演算子ではself assignment適切

  • を処理していない、あなたのオペレータについてのもう一つのコメント=

    • 、私はブーストを使用するためにあなたをお勧めします:: scoped_arrayの代わりに、通常のポインタ。

    私はこれがあなたに問題を起こしているのかどうか分かりませんが、メモリの破損の問題があると思われるため、それに気付くかもしれません。

  • 関連する問題