Documented JOB_LIST guarantees when the CreateProcessW caller terminates

Branislav Lazic 0 Reputation points
2026-11-09T17:20:16.0333333+00:00

I am designing a Windows 10 x64 process supervisor using Windows Job Objects.

The intended implementation uses CreateProcessW with STARTUPINFOEX, EXTENDED_STARTUPINFO_PRESENT, and PROC_THREAD_ATTRIBUTE_JOB_LIST to assign a child process to a Job Object at creation time. The Job Object is configured with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE.

I would like to clarify the documented Windows API guarantees if the calling process unexpectedly terminates during process creation.

Specifically:

If the caller terminates while CreateProcessW is executing, can the newly created process remain running without being assigned to the specified Job Object?

Is Job Object assignment guaranteed to complete before the new process begins executing its initial thread?

If the caller terminates immediately after process creation but before processing the returned handles, what happens to the child process and its Job Object membership?

Does closing the last Job Object handle guarantee termination of all associated processes, assuming no inherited or duplicated handles remain?

Is there a documented transactional or rollback guarantee for process creation with PROC_THREAD_ATTRIBUTE_JOB_LIST when the caller terminates unexpectedly?

Does termination of only the calling thread differ from termination of the entire calling process in this scenario?

I am specifically looking for documented API guarantees rather than behavior observed only in testing.

If these guarantees are not provided, is there a Microsoft-supported alternative design for preventing an unsupervised child process?

Thank you.

Windows development | Windows API - Win32
0 comments No comments

1 answer

Sort by: Most helpful
  1. Harry Nguyen (WICLOUD CORPORATION) 690 Reputation points Microsoft External Staff Moderator
    2026-11-10T03:17:24.3033333+00:00

    Hi @Branislav Lazic , 

    Thank you for the detailed question. Some parts can be answered from Microsoft documentation. Others, mainly what happens when the caller terminates while CreateProcessW is still running, are not covered by any public API contract. I've marked each point clearly below. 

    1. Can the new process run without being assigned to the Job Object if the caller terminates during CreateProcessW? 

    The UpdateProcThreadAttribute reference describes PROC_THREAD_ATTRIBUTE_JOB_LIST as a list of job handles that are assigned to the child process in the order specified. It does not describe the outcome if the caller terminates before the call returns, and neither does the CreateProcessW reference. I could not find documentation that guarantees an outcome for that specific interruption. The lack of documentation does not mean an unassigned child can actually occur. It only means the public API contract does not cover this case. 

    2. Is Job assignment guaranteed to complete before the initial thread runs? 

    The API reference does not state this ordering. However, Microsoft's published guidance does. Raymond Chen's article A more direct and mistake-free way of creating a process in a job object (The Old New Thing, February 2023) explains that the process is assigned to each listed job in turn, and that this happens before the process's initial thread is allowed to run. As a result, the process cannot execute outside the job. The article also explains why the attribute was added: the older pattern of creating the process suspended and then calling AssignProcessToJobObject can leave the child outside the job if the creator crashes between the two steps. Please note that this is a DevBlogs explanation, not API reference text. 

    3. What happens if the caller terminates after process creation but before handling the returned handles? 

    • When a process terminates, all of its kernel object handles are closed. Child processes are not terminated just because their parent terminated (Terminating a Process). 

    Once a process is associated with a job, that association cannot be broken (Job Objects). 

    If the caller's handle was the last handle to the job, closing it triggers JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE, and the system terminates all processes associated with the job (JOBOBJECT_BASIC_LIMIT_INFORMATION). 

    This termination should not be treated as instantaneous. TerminateProcess is asynchronous when it targets another process, and the target cannot exit until its pending I/O has completed or been canceled. 

    4. Does closing the last Job Object handle guarantee termination of all associated processes? 

    Yes. This is the part with a clear documented guarantee. The Job Objects page states that when JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE is set, closing the last job handle terminates all associated processes and then destroys the job. For nested jobs, processes in child jobs are terminated as well. The guarantee depends on these conditions: 

    No other handle keeps the job alive. Kernel objects remain alive as long as any handle exists, including handles opened by name or duplicated with DuplicateHandle (Kernel Objects). An unnamed job with a non-inheritable handle avoids most of these cases. Raymond Chen also notes that an inheritable job handle can be inherited by accident if other code in the process calls CreateProcess with bInheritHandles = TRUE (Destroying all child processes (and grandchildren) when the parent exits, Additional notes on controlling which handles are inherited by CreateProcess). 

    Breakaway is not allowed. If the job sets JOB_OBJECT_LIMIT_BREAKAWAY_OK or JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK, descendants can be created outside the job. Child processes created through Win32_Process.Create are also not associated with the job (Job Objects). 

    5. Is there a documented transactional or rollback guarantee? 

    No. Neither the CreateProcessW reference nor the UpdateProcThreadAttribute reference describes transactional semantics or rollback when the caller terminates during the call. CreateProcessW is also documented to return before the new process has finished initializing. 

    6. Does terminating only the calling thread differ from terminating the whole process? 

    Yes, in a way that matters for your design: 

    Thread only. Handles belong to the process, not the thread (Kernel Objects). If other threads are still running, the process stays alive and its job handle stays open, so KILL_ON_JOB_CLOSE is not triggered. The process terminates only if that thread was its last active thread (Terminating a Thread). 

    Thread killed during the call. TerminateThread warns that terminating a thread while it is running certain Kernel32 calls can leave the process's Kernel32 state inconsistent. The documentation does not describe what happens to a child being created at that moment. 

    Whole process. All handles are closed, so the behavior in point 3 applies. 

    Recommended design based on the documented behavior 

    Create an unnamed job with JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE and no breakaway limits. 

    Keep the job handle non-inheritable. If the child must inherit other handles, list them explicitly with PROC_THREAD_ATTRIBUTE_HANDLE_LIST (CreateProcessW). 

    Use PROC_THREAD_ATTRIBUTE_JOB_LIST instead of creating the process suspended and then calling AssignProcessToJobObject, for the reason explained in point 2. 

    If you want an explicit check before the child runs, also pass CREATE_SUSPENDED. The primary thread does not run until ResumeThread is called (Process Creation Flags). Confirm membership with IsProcessInJob (Job Objects) before resuming the thread. 

    This covers what can be established from public documentation. If your design needs a formal guarantee for the interrupted-call scenario (points 1 and 5), you can request clarification through Windows Developer Support. Please note that this is paid, incident-based support. 

    I hope this helps. If you found it useful, you're welcome to follow this guidance so others with a similar question can find it more easily. 

    Thank you.

    Was this answer helpful?

    0 comments No comments

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.