The debugger may stop responding when mixed-mode debugging a debuggee that uses more than 63 thread local storage slots

This article has been archived. It is offered "as is" and will no longer be updated.
Consider the following scenario. An application is running under a mixed mode debugger, also known as an "interop-debugger." The debuggee has not loaded the common language runtime (CLR). The debuggee allocates more than 63 thread local storage (TLS) slots, and then the debuggee loads the CLR. In this scenario, the debugger stops responding, and the debugger may consume 100 percent of the CPU usage. If the debuggee is stopped by using Task Manager, the debugger becomes responsive again.

Note This problem may also occur with any mixed-mode debugger that uses the ICorDebug interfaces (specifically Microsoft Visual Studio .NET 2002, Visual Studio .NET 2003, and Visual Studio 2005) for those corresponding runtimes.
This problem occurs because the CLR uses TLS slots. The mixed-mode debugger must read the CLR’s TLS slots from out of process, and the mixed-mode debugger does not correctly read slots that have an index above 63.
To work around this problem, use one of the following methods:
  • Use the managed-only debugger or the native-only debugger instead of the mixed-mode debugger.
  • Modify the debuggee to load the CLR early. TLS slots are allocated based on a first-come, first-served basis. Therefore, if the debuggee loads the CLR early, fewer slots will be allocated.
  • Modify the debuggee to reserve fewer TLS slots for the CLR. You can allocate several slots, and then free these slots before the CLR is loaded. To do this, use the following sample code.
    #include "stdafx.h"#include "windows.h"const int NumSlots = 20; DWORD g_slots[NumSlots];// Call this from Main// This "reserves" the low TLS slots for the CLR.void AllocateSlots(){    for(int i = 0; i < NumSlots; i++)    {        g_slots[i] = TlsAlloc();    }}// Call this after your application finishes allocating its own TLS slots, but // before you load any managed code.void FreeSlots(){    for(int i =0; i < NumSlots; i++)    {        TlsFree(g_slots[i]);        g_slots[i] = 0;    }}int _tmain(int argc, _TCHAR* argv[]){    AllocateSlots();    // these are exactly like the slots that are allocated by the application.    DWORD i1 = TlsAlloc();    DWORD i2 = TlsAlloc();    DWORD i3 = TlsAlloc();    DWORD i4 = TlsAlloc();        FreeSlots();    // ....pretend we load the CLR...        // This should now be a low slot    DWORD i5 = TlsAlloc();    	return 0;}

Article ID: 939969 - Last Review: 01/16/2015 03:56:00 - Revision: 3.0

Microsoft .NET Framework 2.0, Microsoft .NET Framework 1.1, Microsoft .NET Framework 1.0

  • kbnosurvey kbarchive kbtshoot kbexpertiseadvanced kbprb KB939969