Skip to content

Latest commit

 

History

History

library-init-thread-join

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 

Library Initializer Thread Join Experiment

Spawning a thread and waiting for its creation then exit from a module initializer or finalizer (the latter being the module subsystem lifetime).

This experiment deadlocks on the ntdll!LdrpInitCompleteEvent event object in the LdrpInitialize function during process startup. During process run-time the deadlock will occur a bit later on the ntdll!LdrpLoadCompleteEvent event object in the LdrpInitializeThreadLdrpDrainWorkQueue function (due to running DLL_THREAD_ATTACH). If it was possible to still continue then thread creation or exit would further block when acquiring the ntdll!LdrpLoaderLock lock in the LdrpInitializeThread function also due to running DLL_THREAD_ATTACH routines at thread startup or DLL_THREAD_DETACH routines at thread exit.

The loader intertwining with the threading implementation as we see here represents an overextension of the loader because those components should have zero knowledge of each other much less share synchronization. In other words, these subsystems are tightly coupled.

Specifying the THREAD_CREATE_FLAGS_SKIP_LOADER_INIT (new in Windows 10) on NtCreateThreadEx can bypass these thread creation and exit blockers. However, I have not seen an occurrence of the Windows API internally spawning a thread with this flag, so these deadlocks remain prevalent.

The funny thing about these deadlocks is that since Ctrl + C on Windows works by spwaning a thread into a process, they hang your entire terminal indefinitely (you need to whip out Task Manager). It can also lock out some Windows debugging tools that work by remotely spawning a thread to break-in a process or ascertain some information about it.