How to check if a HANDLE is valid or not?

58,328

Solution 1

Checking to see whether a handle is "valid" is a mistake. You need to have a better way of dealing with this.

The problem is that once a handle has been closed, the same handle value can be generated by a new open of something different, and your test might say the handle is valid, but you are not operating on the file you think you are.

For example, consider this sequence:

  1. Handle is opened, actual value is 0x1234
  2. Handle is used and the value is passed around
  3. Handle is closed.
  4. Some other part of the program opens a file, gets handle value 0x1234
  5. The original handle value is "checked for validity", and passes.
  6. The handle is used, operating on the wrong file.

So, if it is your process, you need to keep track of which handles are valid and which ones are not. If you got the handle from some other process, it will have been put into your process using DuplicateHandle(). In that case, you should manage the lifetime of the handle and the source process shouldn't do that for you. If your handles are being closed from another process, I assume that you are the one doing that, and you need to deal with the book keeping.

Solution 2

Some WinAPI functions return meaningless ERROR_INVALID_PARAMETER even if valid handles are passed to them, so there is a real use case to check handles for validity.

GetHandleInformation function does the job: http://msdn.microsoft.com/en-us/library/ms724329%28v=vs.85%29.aspx

Solution 3

as the port may close by a external application

This is not possible, an external application cannot obtain the proper handle value to pass to CloseHandle(). Once you have the port opened, any other process trying to get a handle to the port will get AccessDenied.

That said, there's crapware out there that hacks around this restriction by having secret knowledge of the undocumented kernel structures that stores handles for a process. You are powerless against them, don't make the mistake of taking on this battle by doing the same. You will lose. If a customer complains about this then give them my doctor's advice: "if it hurts then don't do it".

Solution 4

If you are given a HANDLE and simply want to find out whether it is indeed an open file handle, there is the Windows API function GetFileInformationByHandle for that.

Depending on the permissions your handle grants you for the file, you can also try to move the file pointer using SetFilePointer, read some data from it using ReadFile, or perform a null write operation using WriteFile with nNumberOfBytesToWrite set to 0.

Solution 5

Probably you are under windows and using ReadFile to read the data. The only way to check it is trying to read. If the HANDLE is invalid it'll return an error code (use GetLastEror() to see which one it is) which will probably be ERROR_HANDLE_INVALID.

Share:
58,328
losingsleeep
Author by

losingsleeep

Updated on July 28, 2022

Comments

  • losingsleeep
    losingsleeep almost 2 years

    In C++, I have opened a serial port that has a HANDLE. Since the port may close by an external application, how can I verify that the HANDLE is still valid before reading data?

    I think it can be done by checking the HANDLE against a suitable API function, but which? Thank you.

  • janm
    janm about 13 years
    Not so. An application with appropriate permissions can use DuplicateHandle() to close a handle in another process. Documented; see the MSDN page.
  • janm
    janm about 13 years
    Careful; calling something like GetCommState isn't sufficient because of the race condition where something else might be opened and the operating systems reuses the handle value.
  • user1703401
    user1703401 about 13 years
    @janm - this assumes that a 2nd process could obtain the handle value. That is highly untrivial when the owning process doesn't cooperate. Requiring the undocumented kernel table hacking or other secret knowledge of the process to read it out of memory.
  • janm
    janm about 13 years
    @hans - Trivial if the handle was passed from another application in the first place and that application remembers the handle value it passed.
  • user1703401
    user1703401 about 13 years
    Covered by the last sentence.
  • janm
    janm about 13 years
    Depends on who owns the other process. Also covered by the last few sentences of my answer! (difference: "do the book keeping" vs. "don't do it"). But yes, I agree that it is a feature that probably should never be used.
  • janm
    janm about 13 years
    But my real issue is that you say "not possible". There is a case where it is possible.
  • user1703401
    user1703401 about 13 years
    Right, it is not possible if everybody follows the operating system rules. The fact that some crapware can break the rules doesn't change that. Putting up defenses against somebody intentionally running crapware like that makes no sense. They did it for a reason, Lord knows why. Maybe it is because your program sucks a certain way. Like not making it easy to the user to terminate it. When you contemplate even doing this, there's a high likelihood that you made the rest of your program suck that way as well. Users are good at finding ways of making sucky programs suck less.
  • janm
    janm about 13 years
    No, it is possible when everybody follows the operating system rules. See the documentation for DuplicateHandle() and note that you can implement CloseHandle() in terms of DuplicateHandle(). I can see cases where a correctly functioning system could use two processes to achieve a good result. That's my only problem with your answer. I agree that bad software "defending" against other processes is misguided and silly, leading to bad outcomes, but factually speaking, the operating system allows this operation without any subterfuge.
  • user1703401
    user1703401 about 13 years
    We're back to my 2nd comment. This isn't going anywhere.
  • losingsleeep
    losingsleeep about 13 years
    Hey guys! in my case the Win32 DLL that opens serial port passes the HANDLE to C# (caller) application, and the C# app can call CloseHandle() Windows API function to close the port any time it wants. i did it and logged the events and checked the port status by HyperTerminal (if it's still open or not) and it works.
  • Synck
    Synck over 8 years
    You can also check the return value of GetCommState to see if the HANDLE is still valid.
  • Robin Hsu
    Robin Hsu over 8 years
    I don't think so. If it is a different thread of the same program, ya, it is possible. But in the first place you have the control since it's your program. Modern OS implementation will just +1 to handle values, which makes collision impossible in a short time. (If your program is written carefully, inside a same program, it is possible to detect this problem.) If your are talking about another process... I believe a process with no ownership of the handle (with the same handle value) will regard it as an invalid handle, otherwise it is a security breach.
  • janm
    janm over 8 years
    @RobinHsu Unix-like OSs allocate the lowest numbered available handle. This makes close(0); dup(h); approach and select() work. On Unix-like systems, yes, you can't close a handle in another process. Windows doesn't make any +1 guarantees. It does make a +4 guarantee so the low-order bits can be used for application purposes. We don't know the lifetime of the value in the code -- for a long-lived process this could be a very long period of time. Correctness shouldn't depend on "a short time". On DuplicateHandle() - with appropriate permissions, another process can cause surprises.
  • Robin Hsu
    Robin Hsu over 8 years
    Thanks. I think I get what you mean. Yet through careful programming, check handle should still be possible. (Well, the program needs to make sure to put a check point where a handle is possibly created. Could be very tedious though, and I agrees with your comments by this tedious one.).
  • janm
    janm over 8 years
    @RobinHsu The real point is that "check handle" can only be correct if you guarantee that the process doesn't open any handles after a close on the handle being checked. Once you make a guarantee that strong you don't need a "check handle" function.
  • Robin Hsu
    Robin Hsu over 8 years
    Not quite true. When the handle is a pipe, it can be closed by the other party. (and is invalidated by the other party). Calling PeekNamedPipe() you will get an error return value, and the error is invalid handle when you call getLastError().
  • janm
    janm over 8 years
    @RobinHsu That is invalidating the pipe itself, not the handle. There is a separate handle for each end of the pipe. You still need to call CloseHandle to release the handle, and calling CloseHandle with that handle value should succeed rather than returning an invalid handle error. If it were closing the handle, there would we a race condition where a dying process communicating with another busy process could lead to the handle value being reused and getting incorrect operation.
  • Robin Hsu
    Robin Hsu over 8 years
    OK. I think you are right. Microsoft seems to reuse the same error code, i.e. invalid handle, in the return value of getLastError() call to indicate end of pipe.
  • Elmue
    Elmue over 2 years
    DuplicateHandle is a quite clumsy function. Why don't you post some example code?
  • Andry
    Andry over 2 years
    @Elmue DuplicateHandle has not much sense without other code. It depends what you want to do.