Reproduced Analysis of deadlock problems caused by improper operation in DllMain--a deadlock occurs when a thread exits

Source: Internet
Author: User

(reproduced in Breaksoftware's CSDN blog)

Let's take a look at the previous examples.

    1. case dll_process_attach: {   
    2.           printf (
    3.           handle hthread = createthread (Null, 0, threadcreateindllmain, null,  0, null);   
    4.            WaitForSingleObject (hthread, infinite);   
    5.            closehandle (hthread);   
    6.       }< span class= "keyword" >break;  

You can imagine the idea of writing a code like this: I want to create a thread when the DLL is first mapped to the process address space, and the thread finishes some operations that might be initialized. Then wait until this thread ends and we continue to do something in DllMain.

Ever wonder if we create a thread here to do things and then wait for the thread to end. This is the synchronous operation, so it is better to put the thread function content in the DllMain directly execute, why start a thread? In reality, it is possible to create a thread when the DLL is first mapped into the process address space and close the thread when the process space is unloaded.

  1. HANDLE g_thread_handle = NULL;
  2. HANDLE g_hevent = NULL;
  3. Static DWORD WINAPI threadcreateindllmain ( lpvoid p)
  4. {
  5. WaitForSingleObject (G_hevent, INFINITE);
  6. return 0;
  7. }
  8. BOOL apientry DllMain ( hmodule hmodule,
  9. DWORD Ul_reason_for_call,
  10. lpvoid lpreserved
  11. )
  12. {
  13. switch (ul_reason_for_call)
  14. {
  15. Case Dll_process_attach:
  16. {
  17. G_hevent =:: CreateEvent (NULL, FALSE, FALSE, NULL);
  18. G_thread_handle =:: CreateThread (NULL, 0, threadcreateindllmain,null, 0, NULL);
  19. } break;
  20. Case Dll_process_detach:
  21. {
  22. :: SetEvent (G_hevent);
  23. :: WaitForSingleObject (G_thread_handle, INFINITE);
  24. :: CloseHandle (G_thread_handle);
  25. G_thread_handle = NULL;
  26. :: CloseHandle (G_hevent);
  27. G_hevent=null;
  28. } break ;
  29. Case Dll_thread_attach:
  30. Case Dll_thread_detach:
  31. Break ;
  32. }
  33. return TRUE;
  34. }

Unfortunately, this program will also deadlock. A slightly sensitive classmate should be able to guess that line 25th is a factor of deadlock. Yes! What about the other one? Must be a thread. After setevent in DllMain, the worker thread revives from the suspended state and executes the return 0. Then another deadlock factor is the logic of the thread exit. We look at the stack

We see that the ldrshutdownthread was called in ExitThread. I used IDA to see the next Ldrshutdownthread function, and the network of Win2K source code to do a comparison. No obvious difference, so I use a more readable version of the Win2K code

VOID2. Ldrshutdownthread (3. VOID4. )  5./*+ + 6.Routine Description:7. This function was called by a thread, which is terminating cleanly.    8. It's purpose is to call all of the processes DLLs to notify them 9. That's the thread is detaching.    10.arguments:11.    None 12.Return value:13. None. 14.--*/   the. {   -.  Ppeb Peb;  -.  Pldr_data_table_entry Ldrdatatableentry;  -.  Pdll_init_routine Initroutine;  +.  Plist_entry Next;  -.  +. Peb =NtCurrentPeb ();  A.  at. Rtlentercriticalsection (&LoaderLock);  -.  -.Try {   -.//   -.//Go in reverse order initialization order and build -.//The unload list in.//   -.  to. Next = peb->ldr->Ininitializationordermodulelist.blink;  +. while(Next! = &Peb->Ldr->ininitializationordermodulelist) {   -. Ldrdatatableentry the. =(pldr_data_table_entry) *.  (Containing_record (next,ldr_data_table_entry,ininitializationorderlinks));  $. Panax Notoginseng. Next = next->Blink;  -.  the.//   +.//Walk through the entire list looking for A.//entries. For each entry, that have an init the.//routine, call it.  +.//   -.  $.if(Peb->imagebaseaddress! = ldrdatatableentry->dllbase) {   $.if( ! (Ldrdatatableentry->flags &ldrp_dont_call_for_threads)) {   -. Initroutine = (pdll_init_routine) ldrdatatableentry->entrypoint;  -.if(Initroutine && (Ldrdatatableentry->flags &ldrp_process_attach_called)) {   the.if(Ldrdatatableentry->flags &Ldrp_image_dll) {   -.if(ldrdatatableentry->TlsIndex) {  Wuyi. Ldrpcalltlsinitializers (ldrdatatableentry->Dllbase,dll_thread_detach);  the. }   -.  Wu.#ifDefined (WX86) -.if(! Wx86processinit | | About. Ldrprunwx86dllentrypoint (Initroutine, $. NULL, -. Ldrdatatableentry->Dllbase, -. Dll_thread_detach, -. NULL A. ) ==Status_image_machine_type_mismatch) +.#endif   the. {   -. Ldrpcallinitroutine (Initroutine, $. Ldrdatatableentry->Dllbase, the. Dll_thread_detach, the.  NULL);  the. }   the. }   -. }   in. }   the. }   the. }   About.  the.//   the.//If The image has a TLS than call its initializers the.//   +.  -.if(LDRPIMAGEHASTLS) { the. Ldrpcalltlsinitializers (NtCurrentPeb ()Imagebaseaddress,dll_thread_detach); Bayi. }   the.  Ldrpfreetls ();  the.  -. }finally {   -.  the. Rtlleavecriticalsection (&LoaderLock);  the. }   the.}
View Code


We looked at line 23rd and found that the function entered the critical section at the beginning, that is, whether or not the thread needs to call DllMain on a DLL to enter the critical section, that is, disablethreadlibrarycalls is not affected when the thread exits the critical section. Because the main thread is calling DllMain, it first enters the critical section and occupies it. And the work thread will enter this critical section before exiting to do something, so it is not going to go in, and is suspended by the system. At this point, the main thread that occupies the critical section waits until the worker thread exits before proceeding to exit the critical section. This creates a deadlock.

Reproduced Analysis of deadlock problems caused by improper operation in DllMain--a deadlock occurs when a thread exits

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.