Skip to content

SamplingTransactionProfilerFactory.Dispose disposes the Task, not the SampleProfilerSession (resource leak) #5418

Description

@tsushanth

Summary

SamplingTransactionProfilerFactory.Dispose() contains a bug where the SampleProfilerSession is never actually disposed, leaving the underlying EventPipeSession open.

Code

File: src/Sentry.Profiling/SamplingTransactionProfilerFactory.cs

public void Dispose()
{
    _sessionTask.ContinueWith(session => session.Dispose());
}

_sessionTask is Task<SampleProfilerSession>. The continuation parameter session is therefore the antecedent Task<SampleProfilerSession>, not the SampleProfilerSession result it wraps. Calling session.Dispose() disposes the Task object, not the session.

Impact

SampleProfilerSession.Dispose() is never called:

// SampleProfilerSession.cs
public void Dispose() => Stop();

private void Stop()
{
    // ...
    _session.Stop();      // EventPipeSession — holds a pipe connection to the .NET runtime
    _session.Dispose();
    EventSource.Dispose();
}

The EventPipeSession holds a connection to the .NET runtime's diagnostics EventPipe. When the profiler factory is disposed (e.g., during SDK shutdown), this connection is left open, causing a resource leak. This is consistent with the Windows Service memory growth reported in #3375, which was linked to Tracing and Profiling being enabled.

Suggested Fix

public void Dispose()
{
    _sessionTask.ContinueWith(
        t => t.Result.Dispose(),
        TaskContinuationOptions.OnlyOnRanToCompletion);
}

This ensures the SampleProfilerSession is disposed only when the task completed successfully (i.e., a session was actually started), which also avoids accessing Result on a faulted or cancelled task.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions