非常奇怪的段错误调用 WinUsb_GetOverlappedResult

Very strange segfault calling WinUsb_GetOverlappedResult

我有这个代码:

void GetResult(WINUSB_INTERFACE_HANDLE InterfaceHandle, LPOVERLAPPED lpOverlapped)
{
    DWORD numBytes = 0;
    WinUsb_GetOverlappedResult(
                InterfaceHandle,
                lpOverlapped,
                &numBytes,
                TRUE
                );
    return;

    uint8_t stack[64];
}

WinUsb_GetOverlappedResult 是一个 __stdcall 函数声明如下:

  WINBOOL WINAPI WinUsb_GetOverlappedResult (WINUSB_INTERFACE_HANDLE InterfaceHandle, LPOVERLAPPED lpOverlapped, LPDWORD lpNumberOfBytesTransferred, WINBOOL bWait);

使用 GCC 5.3.0 (MinGW) 在调试模式下编译一切正常。 (我无法使用 VC++ 进行编译,因为我使用的是 GCC 扩展。)

但是如果我把它改成stack[80]然后它就会出现段错误!!

这是每种情况下的反汇编。 64(不崩溃):

Dump of assembler code for function GetResult(void*, _OVERLAPPED*):
88    {
   0x00408523 <+0>:    push   %ebp
   0x00408524 <+1>:    mov    %esp,%ebp
   0x00408526 <+3>:    sub    [=13=]x68,%esp

89        DWORD numBytes = 0;
   0x00408529 <+6>:    movl   [=13=]x0,-0xc(%ebp)

90        WinUsb_GetOverlappedResult(
91                    InterfaceHandle,
92                    lpOverlapped,
93                    &numBytes,
94                    TRUE
95                    );
=> 0x00408530 <+13>:    movl   [=13=]x1,0xc(%esp)
   0x00408538 <+21>:    lea    -0xc(%ebp),%eax
   0x0040853b <+24>:    mov    %eax,0x8(%esp)
   0x0040853f <+28>:    mov    0xc(%ebp),%eax
   0x00408542 <+31>:    mov    %eax,0x4(%esp)
   0x00408546 <+35>:    mov    0x8(%ebp),%eax
   0x00408549 <+38>:    mov    %eax,(%esp)
   0x0040854c <+41>:    call   0x409d58 <WinUsb_GetOverlappedResult@16>
   0x00408551 <+46>:    sub    [=13=]x10,%esp

96        return;
   0x00408554 <+49>:    nop

97        
98        uint8_t stack[64];
99    }
   0x00408555 <+50>:    leave  
   0x00408556 <+51>:    ret  

和 80(不会崩溃):

Dump of assembler code for function GetResult(void*, _OVERLAPPED*):
88    {
   0x00408523 <+0>:    push   %ebp
   0x00408524 <+1>:    mov    %esp,%ebp
   0x00408526 <+3>:    sub    [=14=]x78,%esp

89        DWORD numBytes = 0;
   0x00408529 <+6>:    movl   [=14=]x0,-0xc(%ebp)

90        WinUsb_GetOverlappedResult(
91                    InterfaceHandle,
92                    lpOverlapped,
93                    &numBytes,
94                    TRUE
95                    );
=> 0x00408530 <+13>:    movl   [=14=]x1,0xc(%esp)
   0x00408538 <+21>:    lea    -0xc(%ebp),%eax
   0x0040853b <+24>:    mov    %eax,0x8(%esp)
   0x0040853f <+28>:    mov    0xc(%ebp),%eax
   0x00408542 <+31>:    mov    %eax,0x4(%esp)
   0x00408546 <+35>:    mov    0x8(%ebp),%eax
   0x00408549 <+38>:    mov    %eax,(%esp)
   0x0040854c <+41>:    call   0x409d58 <WinUsb_GetOverlappedResult@16>
   0x00408551 <+46>:    sub    [=14=]x10,%esp

96        return;
   0x00408554 <+49>:    nop

97        
98        uint8_t stack[80];
99    }
   0x00408555 <+50>:    leave  
   0x00408556 <+51>:    ret    

__stdcall 的作用是添加 sub [=20=]x10,%esp 行,我猜是为了取消函数中的 ret [=21=]x10

无论如何,这些看起来非常相似,我不知道它为什么会崩溃。我什至不能 100% 确定 哪里 它崩溃了(GDB 相当无用)但它在 WinUsb 函数调用附近的某个地方。

很难调试,因为如果我 运行 调试器设置了任何断点,它就不会崩溃。我怀疑这可能与时间有关 - 我还可以通过一些额外的 Sleep(100)s 来防止崩溃。有一次它似乎在 PerfIncrementULongLongCounterValue() 崩溃了,但谁知道呢...

有人知道为什么会发生这种情况吗?

编辑

WinUsb_GetOverlappedResult() 只是根据它的程序集直接调用 GetOverlappedResult(),所以我用它替换了调用。现在你需要 stack[96] 来导致崩溃,但当它发生时它至少告诉我真正的崩溃在哪里(我认为)!

下面是GetOverlappedResult()的反汇编。它在指示的地方崩溃,因为 ebp 是 0.

0x76feaba0                   8b ff                 mov    %edi,%edi
0x76feaba2  <+0x0002>        55                    push   %ebp
0x76feaba3  <+0x0003>        8b ec                 mov    %esp,%ebp
0x76feaba5  <+0x0005>        83 ec 0c              sub    [=15=]xc,%esp
0x76feaba8  <+0x0008>        a1 94 4b 09 77        mov    0x77094b94,%eax
0x76feabad  <+0x000d>        33 c5                 xor    %ebp,%eax
0x76feabaf  <+0x000f>        89 45 fc              mov    %eax,-0x4(%ebp)
0x76feabb2  <+0x0012>        83 7d 14 00           cmpl   [=15=]x0,0x14(%ebp)
0x76feabb6  <+0x0016>        53                    push   %ebx
0x76feabb7  <+0x0017>        56                    push   %esi
0x76feabb8  <+0x0018>        57                    push   %edi
0x76feabb9  <+0x0019>        0f 84 b3 00 00 00     je     0x76feac72 <KERNELBASE!GetOverlappedResult+210>
0x76feabbf  <+0x001f>        83 cf ff              or     [=15=]xffffffff,%edi
0x76feabc2  <+0x0022>        8b 5d 08              mov    0x8(%ebp),%ebx
0x76feabc5  <+0x0025>        83 cb 01              or     [=15=]x1,%ebx
0x76feabc8  <+0x0028>        85 ff                 test   %edi,%edi
0x76feabca  <+0x002a>        0f 84 a9 00 00 00     je     0x76feac79 <KERNELBASE!GetOverlappedResult+217>
0x76feabd0  <+0x0030>        b8 01 00 00 00        mov    [=15=]x1,%eax
0x76feabd5  <+0x0035>        c7 45 f4 01 00 00 00  movl   [=15=]x1,-0xc(%ebp)
0x76feabdc  <+0x003c>        89 45 f8              mov    %eax,-0x8(%ebp)
0x76feabdf  <+0x003f>        84 d8                 test   %bl,%al
0x76feabe1  <+0x0041>        0f 84 5e f3 03 00     je     0x77029f45 <KERNELBASE!GetCurrentProcess+43221>
0x76feabe7  <+0x0047>        6a 00                 push   [=15=]x0
0x76feabe9  <+0x0049>        68 dc 10 f2 76        push   [=15=]x76f210dc
0x76feabee  <+0x004e>        50                    push   %eax
0x76feabef  <+0x004f>        68 ab ab ab ab        push   [=15=]xabababab
0x76feabf4  <+0x0054>        ff 15 68 80 09 77     call   *0x77098068
0x76feabfa  <+0x005a>        8b f0                 mov    %eax,%esi
0x76feabfc  <+0x005c>        85 f6                 test   %esi,%esi
0x76feabfe  <+0x005e>        74 0e                 je     0x76feac0e <KERNELBASE!GetOverlappedResult+110>
0x76feac00  <+0x0060>        8d 45 f4              lea    -0xc(%ebp),%eax
0x76feac03  <+0x0063>        8b ce                 mov    %esi,%ecx
0x76feac05  <+0x0065>        50                    push   %eax
0x76feac06  <+0x0066>        ff 15 5c 8a 09 77     call   *0x77098a5c
0x76feac0c  <+0x006c>        ff d6                 call   *%esi
0x76feac0e  <+0x006e>        33 c0                 xor    %eax,%eax
0x76feac10  <+0x0070>        83 e3 fe              and    [=15=]xfffffffe,%ebx
0x76feac13  <+0x0073>        89 45 f8              mov    %eax,-0x8(%ebp)
0x76feac16  <+0x0076>        39 45 f4              cmp    %eax,-0xc(%ebp)
0x76feac19  <+0x0079>        0f 85 26 f3 03 00     jne    0x77029f45 <KERNELBASE!GetCurrentProcess+43221>
0x76feac1f  <+0x007f>        8b 75 0c              mov    0xc(%ebp),%esi
0x76feac22  <+0x0082>        81 3e 03 01 00 00     cmpl   [=15=]x103,(%esi)
0x76feac28  <+0x0088>        74 26                 je     0x76feac50 <KERNELBASE!GetOverlappedResult+176>

Crash:
0x76feac2a  <+0x008a>        8b 45 10              mov    0x10(%ebp),%eax

0x76feac2d  <+0x008d>        8b 4e 04              mov    0x4(%esi),%ecx
0x76feac30  <+0x0090>        89 08                 mov    %ecx,(%eax)
0x76feac32  <+0x0092>        8b 0e                 mov    (%esi),%ecx
0x76feac34  <+0x0094>        85 c9                 test   %ecx,%ecx
0x76feac36  <+0x0096>        78 31                 js     0x76feac69 <KERNELBASE!GetOverlappedResult+201>
0x76feac38  <+0x0098>        b8 01 00 00 00        mov    [=15=]x1,%eax
0x76feac3d  <+0x009d>        8b 4d fc              mov    -0x4(%ebp),%ecx
0x76feac40  <+0x00a0>        5f                    pop    %edi
0x76feac41  <+0x00a1>        5e                    pop    %esi
0x76feac42  <+0x00a2>        33 cd                 xor    %ebp,%ecx
0x76feac44  <+0x00a4>        5b                    pop    %ebx
0x76feac45  <+0x00a5>        e8 0b f0 02 00        call   0x77019c55 <PerfIncrementULongLongCounterValue+197>
0x76feac4a  <+0x00aa>        8b e5                 mov    %ebp,%esp
0x76feac4c  <+0x00ac>        5d                    pop    %ebp
0x76feac4d  <+0x00ad>        c2 10 00              ret    [=15=]x10
0x76feac50  <+0x00b0>        8b 46 10              mov    0x10(%esi),%eax
0x76feac53  <+0x00b3>        85 c0                 test   %eax,%eax
0x76feac55  <+0x00b5>        74 46                 je     0x76feac9d <KERNELBASE!GetOverlappedResult+253>
0x76feac57  <+0x00b7>        6a 00                 push   [=15=]x0
0x76feac59  <+0x00b9>        57                    push   %edi
0x76feac5a  <+0x00ba>        50                    push   %eax
0x76feac5b  <+0x00bb>        e8 50 01 00 00        call   0x76feadb0 <WaitForSingleObjectEx>
0x76feac60  <+0x00c0>        85 c0                 test   %eax,%eax
0x76feac62  <+0x00c2>        74 c6                 je     0x76feac2a <KERNELBASE!GetOverlappedResult+138>
0x76feac64  <+0x00c4>        e9 fb f2 03 00        jmp    0x77029f64 <KERNELBASE!GetCurrentProcess+43252>
0x76feac69  <+0x00c9>        e8 d2 f1 ff ff        call   0x76fe9e40 <OpenThreadToken+64>
0x76feac6e  <+0x00ce>        33 c0                 xor    %eax,%eax
0x76feac70  <+0x00d0>        eb cb                 jmp    0x76feac3d <KERNELBASE!GetOverlappedResult+157>
0x76feac72  <+0x00d2>        33 ff                 xor    %edi,%edi
0x76feac74  <+0x00d4>        e9 49 ff ff ff        jmp    0x76feabc2 <KERNELBASE!GetOverlappedResult+34>
0x76feac79  <+0x00d9>        8b 75 0c              mov    0xc(%ebp),%esi
0x76feac7c  <+0x00dc>        81 3e 03 01 00 00     cmpl   [=15=]x103,(%esi)
0x76feac82  <+0x00e2>        74 0a                 je     0x76feac8e <KERNELBASE!GetOverlappedResult+238>
0x76feac84  <+0x00e4>        33 c9                 xor    %ecx,%ecx
0x76feac86  <+0x00e6>        8d 45 f8              lea    -0x8(%ebp),%eax
0x76feac89  <+0x00e9>        f0 09 08              lock or %ecx,(%eax)
0x76feac8c  <+0x00ec>        eb 9c                 jmp    0x76feac2a <KERNELBASE!GetOverlappedResult+138>
0x76feac8e  <+0x00ee>        68 e4 03 00 00        push   [=15=]x3e4
0x76feac93  <+0x00f3>        ff 15 c4 80 09 77     call   *0x770980c4
0x76feac99  <+0x00f9>        33 c0                 xor    %eax,%eax
0x76feac9b  <+0x00fb>        eb a0                 jmp    0x76feac3d <KERNELBASE!GetOverlappedResult+157>
0x76feac9d  <+0x00fd>        8b c3                 mov    %ebx,%eax
0x76feac9f  <+0x00ff>        eb b6                 jmp    0x76feac57 <KERNELBASE!GetOverlappedResult+183>
0x76feaca1  <+0x0101>        cc                    int3
0x76feaca2  <+0x0102>        cc                    int3
0x76feaca3  <+0x0103>        cc                    int3
0x76feaca4  <+0x0104>        cc                    int3
0x76feaca5  <+0x0105>        cc                    int3
0x76feaca6  <+0x0106>        cc                    int3
0x76feaca7  <+0x0107>        cc                    int3
0x76feaca8  <+0x0108>        cc                    int3
0x76feaca9  <+0x0109>        cc                    int3
0x76feacaa  <+0x010a>        cc                    int3
0x76feacab  <+0x010b>        cc                    int3
0x76feacac  <+0x010c>        cc                    int3
0x76feacad  <+0x010d>        cc                    int3
0x76feacae  <+0x010e>        cc                    int3
0x76feacaf  <+0x010f>        cc                    int3

好吧,我 我想通了。可能是。我改变的是我不再移动我的 OVERLAPPED 结构。我只能假设 WinUsb 保留了一个指向您在开始写入时传递的 OVERLAPPED 的指针。如果它移动,那么可能会发生故障。

在我能找到 OVERLAPPED 的文档的任何地方都没有提到这一点,但是更改我的代码以便 OVERLAPPED 动态分配一次并且永远不会移动似乎可以阻止崩溃。

不幸的是,我一直没有找到调试它的好方法。最好的方法是使用可逆调试器,但 Windows.

似乎不存在它们