{"id":103538,"date":"2020-03-06T07:00:00","date_gmt":"2020-03-06T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103538"},"modified":"2020-03-05T20:59:59","modified_gmt":"2020-03-06T04:59:59","slug":"20200306-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200306-00\/?p=103538","title":{"rendered":"Why do people take a lock around <CODE>CreateProcess<\/CODE> calls?"},"content":{"rendered":"<p>If you <a href=\"https:\/\/www.youtube.com\/watch?v=gaI6kBVyu00\"> look around<\/a>, you often see people <a href=\"https:\/\/referencesource.microsoft.com\/#System\/services\/monitoring\/system\/diagnosticts\/Process.cs,f7fef721139b19c7\"> take a lock around their calls to the <code>Create\u00adProcess<\/code> function<\/a>. Why do they do that? Isn&#8217;t the <code>Create\u00adProcess<\/code> function thread safe?<\/p>\n<p>Yes, the <code>Create\u00adProcess<\/code> function is thread safe. But thinking about thread safety is the right thing.<\/p>\n<p>The issue is with inheritable handles.<\/p>\n<p>When you ask for handles to be inherited, the <code>Create\u00adProcess<\/code> inherits <i>all<\/i> the handles in the process that are marked as inheritable. If you have multiple threads creating processes, you run into trouble if each thread wants a different set of handles to be inherited. The two threads each create their respective inheritable handles, and as a result, the handles get inherited into <i>both<\/i> processes.<\/p>\n<p>Prior to Windows Vista, the standard workaround was to use a mutex so that only one thread at a time can go through the steps of<\/p>\n<ol>\n<li>Creating inheritable handles.<\/li>\n<li>Calling <code>Create\u00adProcess<\/code> with <code>bInheritHandles = true<\/code>.<\/li>\n<li>Closing the inheritable handles created in step 1.<\/li>\n<\/ol>\n<p>Windows Vista introduced the <code>PROC_<code><\/code>THREAD_<code><\/code>ATTRIBUTE_<code><\/code>LIST<\/code>, which I discussed <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20111216-00\/?p=8873\"> some time ago<\/a>. This addresses the concurrency problem by allowing each call to <code>Create\u00adProcess<\/code> to specify a custom list of handles to be inherited. That way, you can have two threads calling <code>Create\u00adProcess<\/code> at the same time without interfering with each other&#8217;s inherited handles. You don&#8217;t need a mutex any more.<\/p>\n<p>There&#8217;s still a problem with this, though: It requires everybody to be playing the same game.<\/p>\n<p>In order for a handle to be inherited, you not only have to put it in the <code>PROC_<code><\/code>THREAD_<code><\/code>ATTRIBUTE_<code><\/code>LIST<\/code>, but you also must make the handle inheritable. This means that if another thread is not on board with the <code>PROC_<code><\/code>THREAD_<code><\/code>ATTRIBUTE_<code><\/code>LIST<\/code> trick and does a straight <code>Create\u00adProcess<\/code> with <code>bInheritHandles = true<\/code>, it will inadvertently inherit your handles.<\/p>\n<p>A colleague of mine came up with a sneaky trick for addressing this new problem: Create a dummy parent process and put the inheritable handles in there.<\/p>\n<p>Here&#8217;s the basic idea:<\/p>\n<p><b>Preparation<\/b><\/p>\n<ul>\n<li>Create a process suspended. This process will never run. It is just a container for handles.<\/li>\n<\/ul>\n<p>Call this process the &#8220;helper&#8221; process. This process will end up helping us, despite the process not actually doing anything!<\/p>\n<p><b>Process creation<\/b>: Do this each time you need to create a process with specific inherited handles.<\/p>\n<ul>\n<li>Create all the handles as non-inheritable. This ensures they don&#8217;t accidentally get inherited if another thread (not written by you) calls <code>Create\u00adProcess<\/code>.<\/li>\n<li>Use <code>Duplicate\u00adHandle<\/code> to duplicate the handles you want to inherit into the helper process, with <code>bInheritHandles = true<\/code>.<\/li>\n<li>Add those handles to a <code>PROC_<code><\/code>THREAD_<code><\/code>ATTRIBUTE_<code><\/code>LIST<\/code>.<\/li>\n<li>Add the handle of the helper process as a <code>PROC_<code><\/code>THREAD_<code><\/code>ATTRIBUTE_<code><\/code>PARENT_<code><\/code>PROCESS<\/code>, so that it acts as the nominal parent process. Specifically, it is the source of inherited handles.<\/li>\n<li>Call <code>Create\u00adProcess<\/code> with this attribute list.<\/li>\n<li>Use <code>Duplicate\u00adHandle<\/code> with <code>DUPLICATE_<code><\/code>CLOSE_<code><\/code>SOURCE<\/code> to close the handles you injected into the helper process.<\/li>\n<\/ul>\n<p><b>Cleanup<\/b><\/p>\n<ul>\n<li>Terminate the helper process.<\/li>\n<\/ul>\n<p>This technique works because the handles are never marked as inheritable in the main process. Therefore, they can never be accidentally inherited. The only place the handles are marked inheritable is in the helper process. Since the helper process is always suspended, there&#8217;s no way that anybody in the helper process can call <code>Create\u00adProcess<\/code>. The only way somebody can accidentally inherit the handles is if they accidentally get a handle to your helper process, which would be quite an accident.<\/p>\n<p>You probably want to put the helper process in a &#8220;terminate on close&#8221; job, so that the cleanup occurs automatically when your process terminates. That way, you don&#8217;t leak helper processes if your main process crashes before it can clean up properly.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Managing your inheritance.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103538","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>Managing your inheritance.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103538","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103538"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103538\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103538"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103538"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103538"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}