none
How many DLLs can be loaded in a process ( using LoadLibrary() ) RRS feed

  • Question

  • Hello,

    I ran into a problem where a program got error 1114 when loading a DLL.Upon debugging, I found out that this program has loaded many DLLs already. ( by using LoadLibrary() ).

    I wrote a test program which keep loading dlls. I built hundreds of DLLs, each with different name. All of these DLL has no special DllMain. All these DLLs do not depend on other DLLs.

    I then use LoadLibray() to load them. After loading 126 DLLs, I get 1114 (A dynamic link library (DLL) initialization routine failed.) when

    loading the 127th DLL. If I call FreeLibrary() to free one of the previous loaded DLLs, I then was able to load another DLL. So it sure looks like there is a limit. I looked all over MSDN but I can't find any mentioning of this.

    This behavior is consistent on Windows 2003, Windows 2008, x86, or x64.

    Can someone shed some light on this ? Thanks.

    Friday, July 27, 2012 9:31 PM

Answers

All replies

  • There are many, many causes of ERROR_DLL_INIT_FAILED. The TLS slot is one of the quickest exhausted resource that matches your usage pattern.


    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    Friday, July 27, 2012 10:16 PM
  • Hi Sheng,

    Thanks for the answer.

    In MSDN, I see that "The maximum number of indexes per process is 1,088.".

    I previously saw a problem ( totally different problem ) where some code forgot to free the TLS slots, and subsequent TlsAlloc() got a value of FFFFFFFF.  In that problem I saw the limit was indeed 1088. I use !tls -1 to display them in windbg.

    In the current case, I see each DLL running the __CRT_INIT, which calls TlsAlloc(). When loading the 127th DLL,

    TlsAlloc() returned an index of 128.  ( I can see the TlsIndex for the previous DLL loading was 127.. ). So the TlsAlloc() did not fail, but somehow, somewhere, it decided that the dll init should fail.

    Is this decided by __CRT_INIT ? Is that a default value ? Can it be over-ridden ? Thanks..

    Friday, July 27, 2012 11:45 PM
  • Are you writing your own entry point and calling CRT_INIT or using DllMainCRTStartup and DLLMain?

    Do you have global/static variables in the DLL?



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    Saturday, July 28, 2012 12:18 AM
  • My dll has no entry point.

    It contains only the following code:

    #include <windows.h>
    #include <stdlib.h>
    #include <stdio.h>


    int myProc()
    {

       printf("in myProc\n");
       return 0;
    } /* End of main function*/

    No global, no static.

    dumpbin /headers b000.dll | grep entry

     1161D entry point (0801161D) @ILT+1560(__DllMainCRTStartup@12)

    Thanks.

    Saturday, July 28, 2012 2:04 AM
  • That is really strange. What is the version of CRT you are using? What is the OS you are running?

    I have no problem loading thousands of copies of the dll.

    #include "stdafx.h"
    #include "assert.h"
    void LoadLibraryTest(int i)
    {
    	TCHAR exePath[_MAX_PATH];
    	memset(exePath,0,_MAX_PATH*sizeof(TCHAR));
    
    	TCHAR dllPath[_MAX_PATH];
    	memset(dllPath,0,_MAX_PATH*sizeof(TCHAR));
    
    	GetModuleFileName(NULL,exePath,_MAX_PATH);
    	PathCombine(dllPath,exePath,_T("..\\..\\Debug"));
    
    	GUID guid;
    	CoCreateGuid(&guid);
    	LPOLESTR fileName;
    	StringFromCLSID(guid,&fileName);
    	
    	TCHAR fromPath[_MAX_PATH];
    	TCHAR toPath[_MAX_PATH];
    
    	memset(fromPath,0,_MAX_PATH*sizeof(TCHAR));
    	PathCombine(fromPath,dllPath,_T("testdllload.pdb"));
    
    	memset(toPath,0,_MAX_PATH*sizeof(TCHAR));	
    	PathCombine(toPath,dllPath,fileName);
    	PathAddExtension(toPath,_T(".pdb"));
    	CopyFile(fromPath,toPath,true);
    
    	
    	memset(fromPath,0,_MAX_PATH*sizeof(TCHAR));
    	PathCombine(fromPath,dllPath,_T("testdllload.dll"));
    
    	memset(toPath,0,_MAX_PATH*sizeof(TCHAR));	
    	PathCombine(toPath,dllPath,fileName);
    	PathAddExtension(toPath,_T(".dll"));
    
    	CopyFile(fromPath,toPath,true);
    
    	
    
    	HMODULE result=LoadLibrary(toPath);
    	assert(result!=NULL);
    	if(result==NULL)
    	{
    		TCHAR message[512];
    		_stprintf_s(message,512,_T("load library failed at %d th try"),i);
    		OutputDebugString(message);
    	}
    	CoTaskMemFree(fileName);
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    	for(int i=0;i<10000;i++)
    	{	
    		LoadLibraryTest(i);
    	}
    	return 0;
    }
    



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    Saturday, July 28, 2012 3:41 AM
  • That is really strange. What is the version of CRT you are using? What is the OS you are running?

    I have no problem loading thousands of copies of the dll.

    #include "stdafx.h"
    #include "assert.h"
    void LoadLibraryTest(int i)
    {
    	TCHAR exePath[_MAX_PATH];
    	memset(exePath,0,_MAX_PATH*sizeof(TCHAR));
    
    	TCHAR dllPath[_MAX_PATH];
    	memset(dllPath,0,_MAX_PATH*sizeof(TCHAR));
    
    	GetModuleFileName(NULL,exePath,_MAX_PATH);
    	PathCombine(dllPath,exePath,_T("..\\..\\Debug"));
    
    	GUID guid;
    	CoCreateGuid(&guid);
    	LPOLESTR fileName;
    	StringFromCLSID(guid,&fileName);
    	
    	TCHAR fromPath[_MAX_PATH];
    	TCHAR toPath[_MAX_PATH];
    
    	memset(fromPath,0,_MAX_PATH*sizeof(TCHAR));
    	PathCombine(fromPath,dllPath,_T("testdllload.pdb"));
    
    	memset(toPath,0,_MAX_PATH*sizeof(TCHAR));	
    	PathCombine(toPath,dllPath,fileName);
    	PathAddExtension(toPath,_T(".pdb"));
    	CopyFile(fromPath,toPath,true);
    
    	
    	memset(fromPath,0,_MAX_PATH*sizeof(TCHAR));
    	PathCombine(fromPath,dllPath,_T("testdllload.dll"));
    
    	memset(toPath,0,_MAX_PATH*sizeof(TCHAR));	
    	PathCombine(toPath,dllPath,fileName);
    	PathAddExtension(toPath,_T(".dll"));
    
    	CopyFile(fromPath,toPath,true);
    
    	
    
    	HMODULE result=LoadLibrary(toPath);
    	assert(result!=NULL);
    	if(result==NULL)
    	{
    		TCHAR message[512];
    		_stprintf_s(message,512,_T("load library failed at %d th try"),i);
    		OutputDebugString(message);
    	}
    	CoTaskMemFree(fileName);
    }
    int _tmain(int argc, _TCHAR* argv[])
    {
    	for(int i=0;i<10000;i++)
    	{	
    		LoadLibraryTest(i);
    	}
    	return 0;
    }
    



    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    Saturday, July 28, 2012 3:42 AM
  • Hi,

    Your last post helped .

    The difference is that my program was linked with static CRT.

    When I use the /MD flag, it then uses the MSVCRxxx.DLL. Then I can load 300 dlls.( I only tried 300 ).

    In the debugger, I see that TlsAlloc() was called by __CRT_INIT only once.

    By the time it loaded 300 dlls, the !tls -1 shows only 4 indexes allocated.

    ==

    It doesn't matter which version of compiler I use. I tried vs2010, vs2003. Same result.

    ==

    Looks like that there is some kind of limit imposed in __CRT_INIT that the Tls index it gets

    cannot go over 128. Using /MD to compile just prevented that from happening.

    Why 128, I don't know. That question remains.

    I have seen tls index go as high as 1087 in my debugging of other problems. ( And that limit is documented in MSDN. ).

    I searched MSDN again, but I still can't find any mentioning of this behavior.

    Thanks.

    Saturday, July 28, 2012 6:55 PM
  • Since the above code copies the PDB files you should able to step from LoadLibrary into __DllMainCRTStartup.


    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    Saturday, July 28, 2012 7:20 PM
  • Hi,

    The point of failure is in "int __cdecl _mtinit " . ( Called by CRT_INIT )

       if ( (__flsindex = FLS_ALLOC(&_freefls)) == FLS_OUT_OF_INDEXES ) {
                _mtterm();
                return FALSE;       /* fail to load DLL */
            }
    I was loading dlls b000.dll, b001.dll etc all the way up...

    It starts failing for b126.dll

    I dump out the __flsindex each time.

    0:000> db b123!__flsindex l1
    029cd4d8  7d                                               }
    0:000> db b124!__flsindex l1
    02a1d4d8  7e                                               ~
    0:000> db b125!__flsindex l1
    02a6d4d8  7f                                               .
    0:000> db b126!__flsindex
    02abd4d8  ffffffff                        <====This is FLS_OUT_OF_INDEXES.

    ===========

    So it is doing some FLS stuff..

    Sunday, July 29, 2012 12:27 PM
  • Check http://stackoverflow.com/questions/1437422/working-around-fls-limitations-with-too-many-statically-linked-crts


    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful, so they will appear differently to other users who are visiting your thread for the same problem.
    Visual C++ MVP

    • Marked as answer by luitangaaa Monday, July 30, 2012 1:53 PM
    Sunday, July 29, 2012 9:04 PM
  • Hi Sheng,

    So the conclusion is that is working as designed.I won't dig any further. Thanks a lot for your help.

    This kind of problem will be difficult to diagnose in the field, as it can happen to different DLLs at different times.

    Thanks.

    Monday, July 30, 2012 1:59 PM
  • Today's Windows 10 Insider flight includes a big bump in the FLS slot limit. It used to be 128, now it's over 4000. If all goes well in flighting, and no issues are found, expect this to be the new limit in the 19H1 release this year. 

    https://blogs.windows.com/windowsexperience/2019/01/09/announcing-windows-10-insider-preview-build-18312

    Pete (Microsoft)


    http://10rem.net

    Wednesday, January 9, 2019 7:03 PM