3

現在、アプリケーションの 1 つでクラッシュをデバッグしていて、少し奇妙に見えるものに出くわしました。私のアプリケーションでは、_beginthreadex 関数を使用していくつかのスレッドを開始します。ランダムな時点 (場合によっては数時間後) に、スレッドの 1 つが不明な理由でクラッシュします。クラッシュ時のスタック トレースは次のようになります。

my.dll!thread(void * p=0x241e0140)  Line 792 + 0xf bytes    C
msvcr90.dll!__endthreadex()  + 0x44 bytes   
msvcr90.dll!__endthreadex()  + 0xd8 bytes   
kernel32.dll!_BaseThreadStart@8()  + 0x37 bytes 

ここで、thread はスレッドのメイン ループ関数です。ここでは、スレッド関数の上のスタック フレームを省略しました。クラッシュはアクセス違反であり、正確に同じ不良ポインター値を持つ同じ場所で毎回発生します。

ここで考えさせられたのは、スタック トレースで __endthreadex が発生することです。これを小さなサンプルプログラムで再現しようとしましたが、そこでもアクセス違反が発生しました。ただし、スタック トレースは異なって見えます。

test.exe!thread(void * vpb=0x00000000)  Line 9 + 0x3 bytes  C++
test.exe!_callthreadstartex()  Line 348 + 0x6 bytes C
test.exe!_threadstartex(void * ptd=0x000328e8)  Line 326 + 0x5 bytes    C
kernel32.dll!_BaseThreadStart@8()  + 0x37 bytes

対応するコードは次のとおりです。

static unsigned __stdcall thread( void * vpb )
{
    int *a = (int*)0xdeadbeef;
    *a = 0;

    return 1;
}

int main()
{
    HANDLE th = (HANDLE)_beginthreadex( NULL, 0, thread, 0, CREATE_SUSPENDED, NULL );

    for(int i=0; i<INT_MAX;)
    {
        ++i;
    }

    ResumeThread(th);

    for(int i=0; i<INT_MAX;)
    {
        ++i;
    }

    return 0;
}

元のコードはこれに似ていますが、明らかにより複雑です。したがって、スタック トレースの違いが、小さな例を実装するときにコードを変更したことが原因なのか、それともスタックの破損に問題があることを示しているのか、疑問には思っていません。

したがって、私の質問は基本的に次のとおりです。_BaseThreadStart が __endthreadex を呼び出し、それが再びスレッド関数自体を呼び出す可能性はありますか? もしそうなら、私には奇妙に見えるので、誰かがこれが当てはまる理由を説明できますか?これが、クラッシュするスレッドの最初の問題に関連する可能性のある問題を指摘しているかどうかを考えています.

ご提案いただきありがとうございます。

4

0 に答える 0