Skip to content

Memory leak when using ICorDebugEnum::Clone #121925

@Temp1ar

Description

@Temp1ar

Description

Hey, folks. I've noticed unmanaged memory isn't released if you are using public debugging API in a certain way.
The problem is happening if you'll get an CorDbEnumerator and clone it. There is no way to neuter the cloned object and the items array it contain never gets freed.

Reproduction Steps

In our codebase the repro looks like this:
In OnException callback pseudo code is following:

    ICorDebugValue exceptionObjectReference = thread.CorDebugThread.GetCurrentException();
    ICorDebugExceptionObjectValue exceptionValue = GetExceptionValue(exceptionObjectReference);
    
    exceptionValue.EnumerateExceptionCallStack(out ICorDebugExceptionObjectCallStackEnum callStackEnumerator);
    callStackEnumerator.Clone(out ICorDebugEnum exceptionCallStackEnumerator);

    exceptionCallStackEnumerator.Release();
    //exceptionCallStackEnumerator still holds memory after the last release
   //callStackEnumerator is added to the ContinueNeuterList and frees its resources properly.

Run the debugger on any application which throws exceptions from deep call stacks to magnify effect. For example:

using System.Diagnostics;
using System.Text.RegularExpressions;

void CallSync(int i)
{
    if (i == 0)
        throw new Exception("Zero");
 
    CallSync(i - 1);
}

void DoTestSync(int i)
{
    try
    {
        CallSync(i);
    }
    catch (Exception e)
    {
        if (e.Message == "Zero")
        {
            // Debug.WriteLine($"{i}");
        }
    }
}

Console.WriteLine(Environment.Version);

while (true)
{
    DoTestSync(150);
}

Expected behavior

Clone is released either when refCounter == 0 or there is a Neuter() API to free resources

Actual behavior

Overtime debugger leaks native memory and in debug version of runtime I'm getting an assertion:

Microsoft Visual C++ Runtime Library
---------------------------
Debug Assertion Failed!

Program: ...\runtime\artifacts\bin\coreclr\windows.x64.Debug\mscordbi.dll
File: C:\work\other\runtime\src\coreclr\debug\di\rsenumerator.hpp
Line: 120

Expression: IsNeutered()

For information on how your program can cause an assertion
failure, see the Visual C++ documentation on asserts.

(Press Retry to debug the application)

---------------------------
Abort   Retry   Ignore   
---------------------------

Regression?

No response

Known Workarounds

Not use Clone() API and recreate enumerator when needed.

Configuration

.NET 9, 10 and the latest master are affected, probably earlier versions too.

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions