Re: 0x80000003错误

C/C++本地代码调试

0x80000003错误


bigblueapple 2013-02-27, 06:10 上午
这几天碰到一个用户crash dump,是0x80000003错误。

eip 指向调用完RtlExitUserProcess 后面的int 3.在osr上问了,没有什么确切答案。请教张老师和这里的各位高手。

0:029> kbn
  *** Stack trace for last set context - .thread/.cxr resets it
 # ChildEBP RetAddr  Args to Child              
00 0be2faf8 73153412 00000000 0be2fb3c 73153439 ntdll!RtlExitUserThread+0x41
01 0be2fb04 73153438 00000000 bb0a829b 00000000 msvcr90!_endthreadex+0x23 [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 412]
02 0be2fb3c 731534c7 00000000 0be2fb54 75de3677 msvcr90!_callthreadstartex+0x20 [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 348]
03 0be2fb48 75de3677 074c60d8 0be2fb94 77009d72 msvcr90!_threadstartex+0x69 [f:\dd\vctools\crt_bld\self_x86\crt\src\threadex.c @ 326]
04 0be2fb54 77009d72 074c60d8 7cebf9b0 00000000 kernel32!BaseThreadInitThunk+0xe
05 0be2fb94 77009d45 7315345e 074c60d8 00000000 ntdll!__RtlUserThreadStart+0x70
06 0be2fbac 00000000 7315345e 074c60d8 00000000 ntdll!_RtlUserThreadStart+0x1b
0:029> .lastevent
Last event: 1158.7a8: Break instruction exception - code 80000003 (first/second chance not available)

0:029> r
Last set context:
eax=c0000005 ebx=074c60d8 ecx=b3ac0000 edx=08afe538 esi=00000000 edi=00000000
eip=770222b9 esp=0be2faf0 ebp=0be2faf8 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
ntdll!RtlExitUserThread+0x41:
770222b9 cc              int     3
0:029> u eip
ntdll!RtlExitUserThread+0x41:
770222b9 cc              int     3
770222ba 90              nop
770222bb 90              nop
770222bc 90              nop
770222bd 90              nop
770222be 90              nop
ntdll!RtlpFreeTebLanguageList:
770222bf 8bff            mov     edi,edi
770222c1 55              push    ebp
0:029> ub eip
ntdll!RtlExitUserThread+0x25:
7702229d e837fdffff      call    ntdll!LdrShutdownThread (77021fd9)
770222a2 56              push    esi
770222a3 e8b076feff      call    ntdll!TpCheckTerminateWorker (77009958)
770222a8 ff7508          push    dword ptr [ebp+8]
770222ab 56              push    esi
770222ac e873ddfcff      call    ntdll!ZwTerminateThread (76ff0024)
770222b1 ff7508          push    dword ptr [ebp+8]
770222b4 e857b8ffff      call    ntdll!RtlExitUserProcess (7701db10)

Re: 0x80000003错误


格蠹老雷 2013-02-27, 08:58 上午

EAX寄存器中保存了一个很好的痕迹:eax=c0000005,access violation的异常代码,这应该不是巧合...

什么环境下产生的dump?可能交互式调试么? 什么类型的dump?

Re: 0x80000003错误


bigblueapple 2013-02-27, 11:22 上午
这是个最终用户产生的mini dump。这个eax看上去好像是个线索。

附上这个crash的dump.

Re: 0x80000003错误


格蠹老雷 2013-03-01, 13:04 下午

看了下dump,很有趣

从CRT源代码中的threadex.c中可以找到#02栈帧中的_callthreadstartex函数的源代码:

static void _callthreadstartex(void)
{
    _ptiddata ptd;           /* pointer to thread's _tiddata struct */

    /* must always exist at this point */
    ptd = _getptd();

    /*
        * Guard call to user code with a _try - _except statement to
        * implement runtime errors and signal support
        */
    __try {
            _endthreadex (
                ( (unsigned (__CLR_OR_STD_CALL *)(void *))(((_ptiddata)ptd)->_initaddr) )
                ( ((_ptiddata)ptd)->_initarg ) ) ;
    }
    __except ( _XcptFilter(GetExceptionCode(), GetExceptionInformation()) )
    {
            /*
                * Should never reach here
                */
            _exit( GetExceptionCode() );

    } /* end of _try - _except */

}
还有#01号的_endthreadex:

void __cdecl _endthreadex (
        unsigned retcode
        )
{
        _ptiddata ptd;           /* pointer to thread's _tiddata struct */

        ptd = _getptd_noexit();

        if (ptd) {
            /*
             * Free up the _tiddata structure & its subordinate buffers
             *      _freeptd() will also clear the value for this thread
             *      of the FLS variable __flsindex.
             */
            _freeptd(ptd);
        }

        /*
         * Terminate the thread
         */
        ExitThread(retcode);

}
其中的ExitThread就是#00的RtlExitThread。这意味着,这个线程的用户函数已经返回了,开始执行endthreadex,调用系统的线程退出函数了。

断点异常就是RtlExitThread触发的。虽然没有这个函数的源代码,但是看下汇编也不难理解它的逻辑,正常情况下这个函数应该调用系统服务ZwTerminateThread,但是如果当前线程是进程中的最后一个线程,那么RtlExitThread需要调用RtlExitUserProcess,也就是退出进程。

如何知道当前线程是否是最后一个线程呢?那就是RtlExitThread开头所做的调用NtQueryInformationThread 来查询

 77022281 56              push    esi
77022282 6a04            push    4
77022284 8d45fc          lea     eax,[ebp-4]
77022287 50              push    eax
77022288 6a0c            push    0Ch
7702228a 6afe            push    0FFFFFFFEh
7702228c 8975fc          mov     dword ptr [ebp-4],esi
7702228f e814d9fcff      call    ntdll!NtQueryInformationThread (76fefba8)

其中的0C就是枚举 THREADINFOCLASS,代表AmILastThread

根据异常现场,显然是执行了RtlExitUserProcess,如果执行成功的话,就不会返回了,现在看来是执行失败了,返回了一个错误值0xc0000005,还在EAX中。而且CPU继续执行,遇到了下面的INT 3。猜想在源代码中,INT 3上面或许有句注释:never should reach here :-)

如此看来当前线程根本不是最后一个线程,但是却当作了最后一个线程,谬矣!

 

 

 

Powered by Community Server Powered by CnForums.Net