0

I'm trying to debug what looks like deadlock issue, happening on one remote machine. I did not manage to create a reproducible case for on my local machine, and neither does it happen 100% of the time on the remote one.

My main question is : can a file handle linger and still be visible after it is closed by a process?


The code is rather complex, but it looks basically like this:

CFile* file = new CFile;
// ...do stuff with the file
delete file

As far as I can tell from https://learn.microsoft.com/en-us/cpp/mfc/closing-files?view=msvc-160, delete should ensure that the file object closes its handle (in effect calling CloseHandle).

I verified (because of observing additional side-effects) that the program must have gone through the delete call, and at the same time the file is still open 30 minutes later when looking at SysInternals handle.exe.

Asesh
  • 3,186
  • 2
  • 21
  • 31
F.X.
  • 6,809
  • 3
  • 49
  • 71
  • when `CloseHandle` return - handle already destroyed (if it was valid on input) can not linger – RbMm Nov 10 '20 at 14:25
  • 2
    On the other hand, there could be other handles open to the same file. – Raymond Chen Nov 10 '20 at 14:38
  • @Raymond Chen I verified that it is only opened once for that particular process (there are other processes, but they open the file on their own without sharing the handle) – F.X. Nov 10 '20 at 14:40
  • in this case you not call `CloseHandle` or `NtClose`, or may be mistake that handle not reopened / opened several times. possible also `HANDLE_FLAG_PROTECT_FROM_CLOSE` set on this handle, but i doubt in this – RbMm Nov 10 '20 at 14:44
  • @RbMm At this point I'm grasping at straws to be honest, a weird corner case of the Win32 APIs is one of the hypotheses I'm trying to confirm... – F.X. Nov 10 '20 at 14:46
  • @F.X. what you really need - this is good debug/research, if possible reproduce case or catch deadlock. you say that you have deadlock, but how this related to close handle ? also possible that driver is hung during process `IRP_MJ_CLEANUP` and as result your code is hung inside `CloseHandle` but i also doubt in this. but if look under debugger deadlock - almost always possible research this – RbMm Nov 10 '20 at 14:50
  • *Just in case* you're not hitting the `delete` each time - why don't you try to just create the object on the stack, e.g., `CFile file;`. That way, if an exception is thrown that you haven't detected, the destructor for `CFile` will still be called and close the file (and if this fixes the issue, it could make you aware of other issues that aren't being handled). – Phil Brubaker Nov 10 '20 at 14:58
  • @RbMm This is a decades-old and very crusty part of a larger MFC application that involves an half-insane attempt at creating IPC primitives in the form of files. Honestly we should scrap it, but I'm trying to figure out if we can work around the few bugs it has while it's still around. The fact that the handle remains around puzzles me because code right after it has visible side-effects on the filesystem, which indicates that the delete was hit. – F.X. Nov 10 '20 at 15:03
  • *looks like deadlock issue* - but what is look like this ? based on your info think not possible give any concrete answer, except that after `CloseHandle` return - handle is just destroyed (if no `HANDLE_FLAG_PROTECT_FROM_CLOSE` flag on it). under debugger in live system of course visible more info – RbMm Nov 10 '20 at 15:09
  • 1
    If you have access to the remote machine, you can pull a minidump off of the process once it has entered the error state. You can use Task Manager to do so (right-click the process and select *Create dump file*). – IInspectable Nov 10 '20 at 15:19
  • 2
    The handle could have been duplicated by a helper function somewhere. – Raymond Chen Nov 10 '20 at 15:42
  • Maybe App Verifier in Handles mode can help track down where the extra handle is coming from. – Raymond Chen Nov 10 '20 at 17:19
  • @Raymond Chen Thanks so much for the pointers, I'll give them a try! – F.X. Nov 10 '20 at 17:31
  • Wondering if delete really closes the open handle, looked into the MFC code. The CFile destructor calls Close(), but only if the handle is valid and the m_bCloseOnDelete is set. The Open() member will set them both. However, there is one case in which this may not work correctly: if you call Open() for an existing CFile instance with an already open handle, the assertions won't be evaluated in the case of a release build, and the handle and m_bCloseOnDelete values will be overwritten! So maybe check your code for this. – Constantine Georgiou Nov 10 '20 at 18:27
  • 1
    Do they have antivirus software? Maybe temporarily suspend it? It might be accessing the file .. – Andrew Truckle Nov 10 '20 at 22:05
  • 1
    And do yourself a simple log file. Log when you open and when you close. Then count them in the log. Make sure the totals for each match. – Andrew Truckle Nov 10 '20 at 22:06
  • @AndrewTruckle - *It might be accessing the file* - but this not related to handle closed-not closed – RbMm Nov 11 '20 at 06:52
  • After looking, `HANDLE_FLAG_PROTECT_FROM_CLOSE` seems like the only reason a handle could remain (barring an antivirus or something special with kernel access, but while I can't disable ESET here, I doubt it's messing with things this much...). I did not manage to find any other evidence, so I'll accept an answer with these pointers, and I will comment if/when I find new things! – F.X. Nov 17 '20 at 07:35

0 Answers0