简体   繁体   English

为什么 fclose 会挂起/死锁? (视窗)

[英]Why would fclose hang / deadlock? (Windows)

I have a directory change monitor process that reads updates from files within a set of directories.我有一个目录更改监视器进程,它从一组目录中的文件中读取更新。 I have another process that performs small writes to a lot of files to those directories (test program).我有另一个进程对这些目录(测试程序)的大量文件执行小写操作。 Figure about 100 directories with 10 files in each, and about 500 files being modified per second.图大约 100 个目录,每个目录有 10 个文件,每秒大约有 500 个文件被修改。

After running for a while, the directory monitor process hangs on a call to fclose() in a method that is basically tailing the file.运行一段时间后,目录监视器进程挂起对fclose()的调用,该方法基本上是拖尾文件。 In this method, I fopen() the file, check that the handle is valid, do a few seeks and reads, and then call fclose() .在此方法中,我fopen()文件,检查句柄是否有效,进行几次搜索和读取,然后调用fclose() These reads are all performed by the same thread in the process.这些读取都是由进程中的同一个线程执行的。 After the hang, the thread never progresses.挂起后,线程永远不会继续。

I couldn't find any good information on why fclose() might deadlock instead of returning some kind of error code.我找不到任何关于为什么fclose()可能会死锁而不是返回某种错误代码的好信息。 The documentation does mention _fclose_nolock() , but it doesn't seem to be available to me (Visual Studio 2003).该文档确实提到_fclose_nolock() ,但它似乎对我不可用(Visual Studio 2003)。

The hang occurs for both debug and release builds.调试和发布版本都会发生挂起。 In a debug build, I can see that fclose() calls _free_base() , which hangs before returning.在调试版本中,我可以看到fclose()调用_free_base() ,它在返回之前挂起。 Some kind of call into kernel32.dll => ntdll.dll => KernelBase.dll => ntdll.dll is spinning. Some kind of call into kernel32.dll => ntdll.dll => KernelBase.dll => ntdll.dll is spinning. Here's the assembly from ntdll.dll that loops indefinitely:这是 ntdll.dll 无限循环的程序集:

77CEB83F  cmp         dword ptr [edi+4Ch],0 
77CEB843  lea         esi,[ebx-8] 
77CEB846  je          77CEB85E 
77CEB848  mov         eax,dword ptr [edi+50h] 
77CEB84B  xor         dword ptr [esi],eax 
77CEB84D  mov         al,byte ptr [esi+2] 
77CEB850  xor         al,byte ptr [esi+1] 
77CEB853  xor         al,byte ptr [esi] 
77CEB855  cmp         byte ptr [esi+3],al 
77CEB858  jne         77D19A0B 
77CEB85E  mov         eax,200h 
77CEB863  cmp         word ptr [esi],ax 
77CEB866  ja          77CEB815 
77CEB868  cmp         dword ptr [edi+4Ch],0 
77CEB86C  je          77CEB87E 
77CEB86E  mov         al,byte ptr [esi+2] 
77CEB871  xor         al,byte ptr [esi+1] 
77CEB874  xor         al,byte ptr [esi] 
77CEB876  mov         byte ptr [esi+3],al 
77CEB879  mov         eax,dword ptr [edi+50h] 
77CEB87C  xor         dword ptr [esi],eax 
77CEB87E  mov         ebx,dword ptr [ebx+4] 
77CEB881  lea         eax,[edi+0C4h] 
77CEB887  cmp         ebx,eax 
77CEB889  jne         77CEB83F 

Any ideas what might be happening here?有什么想法可能在这里发生吗?

I posted this as a comment, but I realize this could be an answer in its own right...我将此作为评论发布,但我意识到这本身可能是一个答案......

Based on the disassembly, my guess is you've overwritten some internal heap structure maintained by ntdll , and it is looping forever iterating through a linked list.根据反汇编,我的猜测是您已经覆盖了一些由ntdll维护的内部堆结构,并且它永远循环遍历链表。

In particular at the start of the loop, the current list node seems to be in ebx .特别是在循环开始时,当前列表节点似乎在ebx中。 At the end of the loop, the expected last node (or terminator, if you like -- it looks a bit like these are circular lists and the last node is the same as the first, pointer to this node being at [edi+4Ch] ) is contained in eax .在循环结束时,预期的最后一个节点(或终止符,如果你喜欢 - 它看起来有点像这些循环列表,最后一个节点与第一个节点相同,指向该节点的指针位于[edi+4Ch] ) 包含在eax中。 Probably the result of cmp ebx, eax is never equal, because there is some cycle in the list introduced by a heap corruption.可能cmp ebx, eax的结果永远不会相等,因为堆损坏引入的列表中有一些循环。

I don't think this has anything to do with locks, otherwise we would see some atomic instructions (eg. lock cmpxchg , xchg , etc.) or calls to other synchronization functions.我不认为这与锁有任何关系,否则我们会看到一些原子指令(例如lock cmpxchgxchg等)或调用其他同步函数。

I had a same case with file close function.我的文件关闭 function 也有同样的情况。 In my case, I solved by located the close function embedded other function body instead of having own function.在我的情况下,我通过找到嵌入的其他 function 主体而不是拥有自己的 function 来解决问题。

I was also suspicious on (1) the name of file being duplicated (2) Windows scheduling (file IO wasn't completed before next task treading being started. Windows scheduling and multi-threading is behind of the curtain, so it is hard to verify, but I have similar issue when I tried to save many data in ASCII in the loop. Saving on binary solved at this case.)我也怀疑 (1) 被复制的文件的名称 (2) Windows 调度(文件 IO 在下一个任务开始之前没有完成。Windows 调度在幕后,所以它是多线程的,验证,但是当我尝试在循环中以 ASCII 格式保存许多数据时,我遇到了类似的问题。在这种情况下解决了二进制保存问题。)

My environment, IDE: Visual Studio 2015, OS: Windows 7, language: C++我的环境,IDE:Visual Studio 2015,操作系统:Windows 7,语言:C++

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM