There are at least three parts to this problem, so bear with me:
1) CreateProcess has a parameter bInheritHandles, that causes the child process to inherit all of the inheritable handles in the parent process. This option must be set to TRUE to allow the parent to specify stdin, stdout, and stderr handles for the child in the STARTUPINFO parameter.
2) In Win32 deleting and renaming files can fail when there is more than one handle open to the same file.
3) The Microsoft CRT's open() function will by default create inheritable handles. Additionally the file handles created by default suffer from problem 2 above.
This magic combination creates the following operational problem: Library A calls open() and doesn't expect subsequent renames and deletes to fail. Elsewhere in the process another library B is calling CreateProcess with bInheritHandles set to TRUE (to capture stdin/out/err) temporarily creating duplicate handles. Now occasionally library A's file operations fail. Naturally library A and B are maintained by separate people. I also know of another library A' that uses open() and suffers from a similar problem.
This kb article discusses a related problem and solution. However it still relies on calling CreateProcess with bInheritHandles set to TRUE in the parent process, so it doesn't solve this problem.
I am wondering if others have hit this problem and if there isn't a well known solution?
The kb article above essentially implies that calling CreateProcess with bInheritHandles set to TRUE is racy, so my inclination is to fix library B such that it never does that. I would do this by:
Is this a good strategy or is there some better solution? How would you recommend passing the duped handles to the intermediate process in step 3? Is rundll + custom entry point a reliable way to setup the intermediate process in step 1?
You can use the PROC_THREAD_ATTRIBUTE_HANDLE_LIST
extended attribute to explicitly specify exactly which handles a particular process inherits.
Raymond Chen's blog post "Programmatically controlling which handles are inherited by new processes in Win32" includes sample code for doing this.
The short version:
InitializeProcThreadAttributeList() to create an attribute list
UpdateProcThreadAttribute to specify the handles to inherit
lpAttributeList
member set in STARTUPINFOEX
EXTENDED_STARTUPINFO_PRESENT flag set in call to CreateProcess
Requires Windows Vista, so might not have solved the OPs problem when this question was originally asked, but everyone's using Vista or later by now, right? :-)
If you have access to the actual file handles, you can use SetHandleInformation() to remove the HANDLE_FLAG_INHERIT flag before calling CreateProcess().
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With