2017-04-20 89 views
1

我有这样的代码:很奇怪的段错误调用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]那么它出现segfaults!

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

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

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

90  WinUsb_GetOverlappedResult(
91     InterfaceHandle, 
92     lpOverlapped, 
93     &numBytes, 
94     TRUE 
95     ); 
=> 0x00408530 <+13>: movl $0x1,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 <[email protected]> 
    0x00408551 <+46>: sub $0x10,%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 $0x78,%esp 

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

90  WinUsb_GetOverlappedResult(
91     InterfaceHandle, 
92     lpOverlapped, 
93     &numBytes, 
94     TRUE 
95     ); 
=> 0x00408530 <+13>: movl $0x1,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 <[email protected]> 
    0x00408551 <+46>: sub $0x10,%esp 

96  return; 
    0x00408554 <+49>: nop 

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

__stdcall的作用是添加行sub $0x10,%esp我的猜测是在抵消ret $0x10功能。

在任何情况下,这些看起来非常相似,我不知道它为什么会崩溃。我甚至没有100%肯定其中它崩溃(GDB是相当无益的),但它在WinUsb函数调用周围。

这很难调试,因为如果我运行带有任何断点的调试器,它不会崩溃。我怀疑它可能与时间有关 - 我也可以通过一些额外的Sleep(100)来防止碰撞。一旦它似乎崩溃在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 $0xc,%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 $0x0,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  $0xffffffff,%edi 
0x76feabc2 <+0x0022>  8b 5d 08    mov 0x8(%ebp),%ebx 
0x76feabc5 <+0x0025>  83 cb 01    or  $0x1,%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 $0x1,%eax 
0x76feabd5 <+0x0035>  c7 45 f4 01 00 00 00 movl $0x1,-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 $0x0 
0x76feabe9 <+0x0049>  68 dc 10 f2 76  push $0x76f210dc 
0x76feabee <+0x004e>  50     push %eax 
0x76feabef <+0x004f>  68 ab ab ab ab  push $0xabababab 
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 $0xfffffffe,%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 $0x103,(%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 $0x1,%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 $0x10 
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 $0x0 
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 $0x103,(%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 $0x3e4 
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 
+0

哪里具体异常? – RbMm

+0

对不起,我不明白。 – Timmmm

+0

异常是在哪里?这里不明白?以及“GetOverlappedResult”的组合列表? – RbMm

回答

1

嗯,我想这出。也许。我改变的是我不再移动我的OVERLAPPED结构。我只能假设WinUsb保留一个指向您开始写入时通过的OVERLAPPED的指针。如果它移动,那么可能事情就会中断。

这是没有提到的任何地方我可以找到int OVERLAPPED的文档,但更改我的代码,以便OVERLAPPED动态分配一次,永不移动似乎停止崩溃。

不幸的是我从来没有找到一个好方法来调试它。最好的方法是一个可逆的调试器,但它们似乎不适用于Windows。

+1

是的,这可以解释它。 Windows保留指向“OVERLAPPED”结构的指针副本,并在I/O完成时写入Internal(内部)和InternalHigh(内核)成员。它可能也读取它。在[同步和异步I/O](https://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v = vs。vs)中描述了不释放或修改'OVERLAPPED'结构的要求。 85)的.aspx)。不幸的是,'OVERLAPPED'的文档没有直接提到这一点。这是微软认为显而易见的事情之一,我猜。 –

+0

啊哈很好找!很高兴知道这不是一种侥幸。我打算捅MS去更新他们的文档。 – Timmmm

+0

好的,我向几个MSDN页面提交了反馈,例如'OVERLAPPED','GetOverlappedResult','WinUsb_WritePipe'。如果你在2018年阅读这篇文章,但他们仍然没有提及它,那么至少你知道MSDN页面上的“反馈”选项不起作用。 – Timmmm