4

I have witnessed a Delphi 6 program that uses FindFirst() from SysUtils inside a function. This is a program that runs for months and performs this operation hundreds of times. The surprising thing is that FindClose() is not called and nothing bad happens.

If I understand that correctly, the program seems to leak file Handles. (In the TSearchRec record there is a THandle entry. The whole record is discarded and the THandle not closed). The thing is that there seems to be no problem. I used process explorer form sysinternal and observed no open file handle to the file found by FindFirst.

Any explanation?

  • Related : http://stackoverflow.com/q/32357314/327083 – J... Apr 08 '16 at 15:46
  • Also Related : [Pushing the Limits of Windows](https://blogs.technet.microsoft.com/markrussinovich/2009/09/29/pushing-the-limits-of-windows-handles/) – J... Apr 08 '16 at 15:57
  • 2
    Note that FindFirst closes the handle itself if it can't find a match. – Sertac Akyuz Apr 08 '16 at 16:35
  • Also note that *hundreds of times* over *months* isn't a lot. *Hundreds of times in a minute* is meaningful. Windows releases orphaned handles after some period of times has elapsed without them being accessed. There's a lot of difference between *I spent a thousand dollars for coffee over the last 6 months* and *I spent a thousand dollars on coffee this week*. Over 6 months, your bank account might not notice so much because you deposit every couple of weeks; this week, it probably would. – Ken White Apr 09 '16 at 03:58
  • What is the limit on handles? It used to be in the order of a few thousands. If you additionlly have a cumulative leakage then I see an issue. By cumulative leakage I mean "Windows releases orphaned handles" does not occur. Does it really? I did not know that. I have to look for references on that. – Spyros Komninos Apr 09 '16 at 09:35

1 Answers1

9

As described, your program leaks handles. If you call FindFirst without subsequently calling FindClose, you leak handles. Do that enough and the program will exhaust the available handle objects and fail.

That you don't see that suggests that you have not yet reached the limit. That you do not observe the leak from Process Explorer suggests that you are not looking at the right information. Or perhaps you have mis-diagnosed the problem completely and either the code that leaks is not called, or the call to FindClose is made but you have not found it yet.

Rather than spending much more time analysing this, you should fix your code. The bottom line is that unless you match calls to FindFirst with calls to FindClose, your program leaks.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Or maybe the program exhausted handles but for topic starter it looks like "nothing bad happens". Indeed, if FindFirst can not open handle - it would fail without big bangs. IT would not throw exceptions or OS sygnals - it would just return error condition and do nothing. it can go one for weeks and it would look like nothing bad happens, just one part of the program silently is no more being invoked. – Arioch 'The Apr 08 '16 at 15:00
  • @Arioch'The I think handles come from a common pool though. Once you've exhausted them, then you will get failures elsewhere. – David Heffernan Apr 08 '16 at 15:17
  • Windows will let you have something like 16 million handles before complaining (at least on 64-bit OS). You're more likely to run into trouble with memory limits - search handles are handles to objects in session memory (not process memory) so the OS will happily just page away. Especially on a 64-bit system, this type of leak is more likely to cripple the system (perf-wise) before it actually generates an error. – J... Apr 08 '16 at 15:55
  • I can not test that right now so I just ask. Suppose a FindClose call was made and I did not spot it. What happens when FindClose is called twice. Is that safe? – Spyros Komninos Apr 08 '16 at 17:46
  • 1
    @SpyrosKomninos As always, [the documentation](https://msdn.microsoft.com/en-ca/library/windows/desktop/aa364413%28v=vs.85%29.aspx) is your friend. If the handle is invalid or the function fails for whatever reason the return value is zero. In the case that the return value is zero (function failed), you can check for extended error information in the regular way by calling `GetLastError`. – J... Apr 08 '16 at 17:55
  • 1
    That's the documentation for `Windows.FindClose`, @J..., whereas the topic here is `SysUtils.FindClose`. The latter doesn't return anything, and [its documentation](http://docwiki.embarcadero.com/Libraries/Seattle/en/System.SysUtils.FindClose) is silent on erroneous usage. *The source* can still be your friend, though, and according to the source for the version I have, calling `SysUtils.FindClose` twice on the same `TSearchRec` is a no-op. – Rob Kennedy Apr 08 '16 at 18:55
  • @RobKennedy Fair point. I always default to MSDN for WinAPI wrappers in the RTL out of habit. Surprised that the RTL swallows this return value but, given that there's not much you really need to be concerned about when this fails, I guess it's fine. Usually the WinAPI stuff is implemented almost verbatim. – J... Apr 08 '16 at 18:58
  • 1
    It's really easy to write the code to be sure you call FindClose exactly once. – David Heffernan Apr 08 '16 at 19:01
  • In my specific case it is. The TSearchRec and all that (FindFirst, etc) are isolated in a 10 line code segment in a function. TSearchRec is a local var, so I trust Pascals type safety will not be leaky as an abstraction. – Spyros Komninos Apr 08 '16 at 20:24