Skip to content

Commit a4bdd51

Browse files
committed
Clone IDiagnosticsLogger to avoid references to Interceptors in compiled queries (and memory leak)
1 parent 85b57af commit a4bdd51

File tree

6 files changed

+37
-2
lines changed

6 files changed

+37
-2
lines changed

src/EFCore.InMemory/Query/Internal/InMemoryShapedQueryCompilingExpressionVisitor.QueryingEnumerable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public QueryingEnumerable(
3434
_innerEnumerable = innerEnumerable;
3535
_shaper = shaper;
3636
_contextType = contextType;
37-
_logger = logger;
37+
_logger = logger.CloneWithoutInterceptor();
3838
}
3939

4040
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)

src/EFCore/Diagnostics/IDiagnosticsLogger`.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,7 @@ public interface IDiagnosticsLogger<TLoggerCategory> : IDiagnosticsLogger
3232
/// Holds registered interceptors, if any.
3333
/// </summary>
3434
IInterceptors Interceptors { get; }
35+
36+
IDiagnosticsLogger<TLoggerCategory> CloneWithoutInterceptor();
3537
}
3638
}

src/EFCore/Internal/DiagnosticsLogger.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,24 @@ public DiagnosticsLogger(
4646
Interceptors = interceptors;
4747
}
4848

49+
/// <summary>
50+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
51+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
52+
/// any release. You should only use it directly in your code with extreme caution and knowing that
53+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
54+
/// </summary>
55+
private DiagnosticsLogger(
56+
[NotNull] ILogger logger,
57+
[NotNull] ILoggingOptions loggingOptions,
58+
[NotNull] DiagnosticSource diagnosticSource,
59+
[NotNull] LoggingDefinitions loggingDefinitions)
60+
{
61+
Logger = logger;
62+
Options = loggingOptions;
63+
DiagnosticSource = diagnosticSource;
64+
Definitions = loggingDefinitions;
65+
}
66+
4967
/// <summary>
5068
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
5169
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
@@ -86,6 +104,15 @@ public DiagnosticsLogger(
86104
/// </summary>
87105
public virtual LoggingDefinitions Definitions { get; }
88106

107+
/// <summary>
108+
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
109+
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
110+
/// any release. You should only use it directly in your code with extreme caution and knowing that
111+
/// doing so can result in application failures when updating to a new Entity Framework Core release.
112+
/// </summary>
113+
public virtual IDiagnosticsLogger<TLoggerCategory> CloneWithoutInterceptor()
114+
=> new DiagnosticsLogger<TLoggerCategory>(Logger, Options, DiagnosticSource, Definitions);
115+
89116
/// <summary>
90117
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
91118
/// the same compatibility standards as public APIs. It may be changed or removed without notice in

src/EFCore/Query/QueryCompilationContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public QueryCompilationContext(
4040
Model = dependencies.Model;
4141
ContextOptions = dependencies.ContextOptions;
4242
ContextType = context.GetType();
43-
Logger = dependencies.Logger;
43+
Logger = dependencies.Logger.CloneWithoutInterceptor();
4444

4545
_queryTranslationPreprocessorFactory = dependencies.QueryTranslationPreprocessorFactory;
4646
_queryableMethodTranslatingExpressionVisitorFactory = dependencies.QueryableMethodTranslatingExpressionVisitorFactory;

test/EFCore.Relational.Tests/TestUtilities/FakeDiagnosticsLogger.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ public void Log<TState>(
3535

3636
public IDisposable BeginScope<TState>(TState state) => null;
3737

38+
public IDiagnosticsLogger<T> CloneWithoutInterceptor()
39+
=> new FakeDiagnosticsLogger<T>();
40+
3841
public virtual LoggingDefinitions Definitions { get; } = new TestRelationalLoggingDefinitions();
3942

4043
public IInterceptors Interceptors { get; }

test/EFCore.Specification.Tests/TestUtilities/TestLogger`.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ public class TestLogger<TCategory, TDefinitions> : TestLogger<TDefinitions>, IDi
1010
where TDefinitions : LoggingDefinitions, new()
1111
{
1212
public IInterceptors Interceptors { get; }
13+
14+
public IDiagnosticsLogger<TCategory> CloneWithoutInterceptor()
15+
=> new TestLogger<TCategory, TDefinitions>();
1316
}
1417
}

0 commit comments

Comments
 (0)