異なるメソッドが呼び出され「run-time check failure #0」になる

[戻る]
あいだ 2012/10/25(木) 10:45:54
(環境)Windows7/VC++2010

TestMngクラスに新規にメソッドSetTestClassを作成し、TestCtrlクラスから呼び出しを
行いました。
リビルドを行い動かしてみたところ、TestCtrlクラスでSetTestClassを呼び出している
ところで、なぜか既存のTestMng::UpdateNum関数を呼び出し、エラー(run-time check 
failure #0)が発生しています。

作成した関数SetTestClassと、実際に呼び出されている関数UpdateNumはまったく内容が
異なるため、エラーになるのは当然なのですが、なぜ別の関数UpdateNumが呼び出されて
しまうのでしょうか。

なお、実行対の作成はクリーン&リビルドで全コンパイル・フルリンクを行っており、
ソース上で右クリックから呼び出し先の参照をしたときには、新規に作成した
SetTestClassメソッドにジャンプしています。



TestCrtl::SetTestClass(void)
{
    TestClass* pTest = new TestClass();
    m_pTestMng->SetTestClass(pTest);     //←ここでUpdateNumを呼び出し、エラー
     :
     :
    return;
}

//既存関数
TestMng::UpdateNum(int a ,int b)
{
    //UpdateNumの処理
}

//追加関数
TestMng::SetTestClass(TestClass* pTest)
{
    m_pTestClass = pTest;
}


エラー番号で検索してみましたが解決策が見つかりませんでした。
正しい関数を呼び出すようにするにはどのようにすればいいのでしょうか。

どうぞよろしくお願いします。

tetrapod 2012/10/25(木) 13:40:31
check failure #0 の後ろに The value of ESP was no properly saved うんぬん
というメッセージが出ているのだとしたら、メッセージのとおりで
関数呼び出しの前後で正しく ESP レジスタの値が保存されていない。
つまり「関数呼び出しが正しくない」わけだ。

関数ポインタを経由して呼び出しているのであれば、呼び出し規約の誤り。
よくあるのは GetProcAddress の結果のキャストが間違っているなど。

この例においては、ソースコード上の見た目上は上記に該当しなさそうなので、
原因は「メモリ破壊」だと思われる。
当該行に到達する以前にメモリ破壊するコードが実行されてしまっている
→そのバグが TestMng の vptr や vtbl を壊している
→たまたま違う関数が呼ばれているかのごとく見える

誤キャスト(の結果としてメモリ破壊に見えている)可能性もありそう。

ということで、提示してある箇所には何の問題も無いに1票。
メモリ破壊=ここにいたるまでの全処理を再チェックする必要があると思われる。
まずは m_pTestMng の値が正しいかどうか、からかな。

# 上記はコンパイラのバグでないとしたら、の話。
# VS2010 SP1 はちゃんと当ててあるかな?

あいだ 2012/10/25(木) 19:30:14
>tetrapodさん

ご回答ありがとうございます。
やっぱり(見た目上)処理は問題ないように思えますよね……。

m_pTestMngも、デバッガ上では正常であるように見えます。

極所的な問題ではなさそうなので、この部分だけでなく、全体的に流れを追いながら確
認するしかないようですね。

# もしや……と思いつつ確認しましたが、無事(?)SP1は当たっていました。

ひとつずつ丁寧に確認していこうと思います。
ありがとうございました!

forty-five 2012/10/25(木) 21:56:13
私の環境は VC6 なんですけど、
メンバ関数の戻り型を指定してないと不思議な挙動になります。

class X
{
public:
    foo(); // 普通は int foo(); とかにする。
};

X::foo()
{
}

void main()
{
    X x;
    int n = x.foo();
    // n は 0xCCCCCCCC
}

X::foo() で何も返却していないのに構文上は値を受け取れます。
関数の戻り型をちゃんと記述してみてはいかがでしょうか。

あいだ 2012/10/26(金) 17:50:27
> forty-fiveさん

ご回答ありがとうございます。
自分の記載ミスであり、実際のソース上では返却型定義をしております。
申し訳ありません。


class TestCtrl
{
private:
  //Mngとの連携用
    TestMng* m_pTestMng;   //初期化等はInitで実施

public:
    //連携しているMngに対し、Ctrlで操作したデータクラスを設定
    void SetTestClass(void);
};


class TestMng
{
private:
     m_pTestClass;   //初期化等はInitで実施

public:

    //既存関数:データ更新
    long UpdateNum(int a ,int b);

    //新規作成:Mngにデータクラスを設定
    void SetTestClass(TestClass* pTest);
};

bun 2012/10/30(火) 09:25:27
参考までに、メモリ破壊で別の関数が呼ばれる仕組みです。

http://www.ipa.go.jp/security/awareness/vendor/programmingv1/b06_01.html

ITO 2012/11/08(木) 10:02:50
> ひとつずつ丁寧に確認していこうと思います。
こういった症状は、ステップでのデバッグは効かないと思います。
 ありえそうなところにブレークさせてどこまで変数が有効になっているか
みていくのがいいと思います。

あいだ 2012/11/09(金) 17:29:02
[[解決]]
ご回答いただきました皆様、ありがとうございました。

事象そのものは解決せず、別の開発端末にソースをそっくり持っていって全コンしたと
ころ、なぜか解決しました。

その後(情けないことですが、私の手には負えないということで)サポートチームが調
査を行ったのですが、私の端末自体がおかしくなっていたらしい、という報告を受け、
端末をOS再インストールから再構築したところ、自端末でも無事望みどおりのメソッド
が呼ばれるようになりました。

プログラミングの技術が原因ではなかったようで、結果的に板違いのようになってしま
い申し訳ありません。

これにてクローズさせていただきます。
やはり開発をするにあたってはPG以外の知識もそれなり以上に必要ですね……
ありがとうございました。

古いスレッドには追加発言できません。