TL;DR;
Windows HANDLEs are used to represent objects such as Events, Files, Processes and Threads. HANDLEs are typedef’d as a pointer-sized type but Windows only uses 32 bits (with sign extension) so that 32 and 64 bit processes can interoperate.
Windows HANDLEs are generally returned by Windows APIs that create or open objects, and must be closed once the object is no longer in use to conserve system resources. HANDLEs to the same object might have different access rights (for instance, a process handle might only allow waiting on exit, or might allow full memory access). HANDLEs can also be duplicated, both within the process that created them (to allow code with different lifetimes to refer to the same underlying object), and to other processes.
HANDLE has several quirks. Many Windows APIs take or return pseudo handle values, such as the return from ::GetCurrentProcess() or ::GetCurrentThread(). These pseudo handle values may overlap with return values from some handle manipulation functions, and malicious code could send these placeholder values from less privileged processes.
In particular, GetCurrentProcess() == INVALID_HANDLE_VALUE. Code must be very careful not to use these pseudo handle values accidentally. For instance, code might intend to open and send a file handle to a renderer, but if the file opening failed it might accidentally provide INVALID_HANDLE_VALUE as the source handle to DuplicateHandle(), resulting in a handle to the current process being sent to the renderer, which would be a serious security bug.
In general it should not be necessary for Chromium code to directly manipulate Windows HANDLEs, and instead code should use abstractions such as base::File. Chromium, via mojo, makes it easy to send appropriately wrapped objects to children using mojo_base wrappers.
In Chromium, HANDLEs should always be owned by a base::win::ScopedHandle and their underlying HANDLE should only be accessed when a related Windows API is called. This ensures that HANDLEs are not leaked and that ownership of the underlying object in Chromium code is clear. ScopedHandle refuses to adopt or represent pseudo handle values, and will not return them from its .get() accessor.
When duplicating a ScopedHandle’s underlying HANDLE always call ScopedHandle::is_valid() before calling DuplicateHandle, and return an empty ScopedHandle or a raw nullptr HANDLE if duplication fails.
When adopting a HANDLE value into a base::win::ScopedHandle that another process duplicated into the current process (e.g. a log file handle on a command line) use base::win::TakeHandleOfType() to validate that the HANDLE is not a pseudo handle and points to a valid object before adopting it.
If you must manipulate HANDLEs directly, the following guidelines apply:
Do not store pseudo handles, and instead simply call ::GetCurrentProcess() when you need the pseudo handle value. If you need a real handle to a process (and base::Process does not provide what you need), you must duplicate to a real HANDLE before adopting it.
Use nullptr to represent uninitialized or invalid values. In code that manages its own HANDLEs use nullptr to initialize all HANDLE variables and members and return nullptr from any accessor that returns a raw HANDLE while the wrapper object is invalid. Use base::win::IsPseudoHandle() to validate HANDLE values provided to constructors (do not just check handle != INVALID_HANDLE_VALUE).