Raymond Chen describes a technique using a helper process to precisely control which handles are inherited by a new process, avoiding accidental inheritance from other components in the same process.
<p>Some time ago, I wrote about <a title="Programmatically controlling which handles are inherited by new processes in Win32" href="https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873"> programmatically controlling which handles are inherited by new processes in Win32</a> by using the <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code> to limit exactly which handles are inherited. That way, when you create a new process, you have precise control over which handles get inherited and don’t accidentally inherit handles created by unrelated components in your process.</p>
<p>A collegue of mine pointed out that you still have the reverse problem: Since handles must be marked as inheritable for them to participate in <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>, if another thread calls <code>CreateProcess</code> with <code>bInheritHandles</code> = <code>TRUE</code> but without using <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>, then they will accidentally inherit all of <i>your</i> handles.</p>
<p>This problem could have been avoided if the <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code> allowed you to include non-inheritable handles, in which case they would be non-inheritable by normal <code>CreateProcess</code> but inheritable if explicitly opted back in. But alas, that’s not how it was designed.</p>
<p>Instead, you can create a helper process. All this helper process does is wait for the main process to exit, and then exit itself.</p>
<pre>WaitForSingleObject(hMainProcess, INFINITE);
ExitProcess(0);
</pre>
<p>This process doesn’t sound like it’s doing anything useful, and it’s not. But what makes it useful is not what it’s doing but rather what is done <i>to</i> it.</p>
<p>The components in the main process create their handles as non-inheritable. When they wants to create a process with specific inherited handles, they duplicate the desired handles into the helper process (as inheritable), and then build a <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code> that lists those duplicates as handles to inherit. They also use the <code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />PARENT_<wbr />PROCESS</code> to specify that the <i>helper</i> process is the parent process that the handles should be inherited from. Then they pass those thread attributes to <code>CreateProcess</code>, and the new process will inherit exactly those handles. Then they clean up by closing the handles in the helper process with the help of <code>DuplicateHandle</code> and <code>DUPLICATE_<wbr />CLOSE_<wbr />SOURCE</code>.</p>
<p>Notice that multiple threads can simultaneously be operating on the helper process in this way, so you need only one helper process to service all your handle-inheritance-control needs.</p>
<p>This avoids the accidental inheritance problem because the handles that belong to the components in the main process are still marked non-inheritable, so any other code in the main process that does a <code>CreateProcess</code> will not inherit them.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260511-00/?p=112313">Additional notes on controlling which handles are inherited by <CODE>Create­Process</CODE></a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
# Additional notes on controlling which handles are inherited by CreateProcess - The Old New Thing
Source: [https://devblogs.microsoft.com/oldnewthing/20260511-00?p=112313](https://devblogs.microsoft.com/oldnewthing/20260511-00?p=112313)
Some time ago, I wrote about[programmatically controlling which handles are inherited by new processes in Win32](https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873)by using the`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`to limit exactly which handles are inherited\. That way, when you create a new process, you have precise control over which handles get inherited and don’t accidentally inherit handles created by unrelated components in your process\.
A collegue of mine pointed out that you still have the reverse problem: Since handles must be marked as inheritable for them to participate in`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`, if another thread calls`CreateProcess`with`bInheritHandles`=`TRUE`but without using`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`, then they will accidentally inherit all of*your*handles\.
This problem could have been avoided if the`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`allowed you to include non\-inheritable handles, in which case they would be non\-inheritable by normal`CreateProcess`but inheritable if explicitly opted back in\. But alas, that’s not how it was designed\.
Instead, you can create a helper process\. All this helper process does is wait for the main process to exit, and then exit itself\.
```
WaitForSingleObject(hMainProcess, INFINITE);
ExitProcess(0);
```
This process doesn’t sound like it’s doing anything useful, and it’s not\. But what makes it useful is not what it’s doing but rather what is done*to*it\.
The components in the main process create their handles as non\-inheritable\. When they wants to create a process with specific inherited handles, they duplicate the desired handles into the helper process \(as inheritable\), and then build a`PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`that lists those duplicates as handles to inherit\. They also use the`PROC\_THREAD\_ATTRIBUTE\_PARENT\_PROCESS`to specify that the*helper*process is the parent process that the handles should be inherited from\. Then they pass those thread attributes to`CreateProcess`, and the new process will inherit exactly those handles\. Then they clean up by closing the handles in the helper process with the help of`DuplicateHandle`and`DUPLICATE\_CLOSE\_SOURCE`\.
Notice that multiple threads can simultaneously be operating on the helper process in this way, so you need only one helper process to service all your handle\-inheritance\-control needs\.
This avoids the accidental inheritance problem because the handles that belong to the components in the main process are still marked non\-inheritable, so any other code in the main process that does a`CreateProcess`will not inherit them\.
### Category
### Topics
## Author

Raymond has been involved in the evolution of Windows for more than 30 years\. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie\-jeebies\. The Web site spawned a book, coincidentally also titled The Old New Thing \(Addison Wesley 2007\)\. He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information\.
A blog post proposing a redesign of the System.Diagnostics.Process class in .NET to separate properties valid only for started processes into a new class, aiming to reduce API confusion.
This article from Microsoft's Old New Thing blog explains the rationale behind best practices for Windows kernel callback functions, particularly why blocking or waiting on work items defeats their purpose, using a cautionary tale about drivers causing system hangs.
The article examines the pitfalls of altering API behavior depending on the linked SDK version, using Windows' CoInitializeSecurity as a case study. It discusses issues with DLL version mismatches and tail call optimization that complicate this approach.
A developer shares an architectural pattern to manage context window bloat in continuous Anthropic agent loops, using KV caching, dynamic tool schema loading, and decoupling executor/advisor roles with Claude 3.5 Sonnet and Claude 3 Opus.
A proposal to add spawn templates to the Linux kernel aims to optimize the fork+exec pattern by caching executable information, though the current patch set is unlikely to be accepted as-is.