Skip to content

Commit 6eefcfb

Browse files
Factor out class to minimize chance of mixing up two handlers
1 parent 269b2b5 commit 6eefcfb

File tree

1 file changed

+43
-40
lines changed

1 file changed

+43
-40
lines changed

CodeConverter/Shared/RoslynCrashPreventer.cs

Lines changed: 43 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@ namespace ICSharpCode.CodeConverter.Shared
77
{
88
internal static class RoslynCrashPreventer
99
{
10-
private static readonly object _exchangeLock = new object();
10+
private static readonly DelegatingHandler _codeAnalysisHandler= new DelegatingHandler(typeof(Compilation).Assembly, "Microsoft.CodeAnalysis.FatalError");
11+
private static readonly DelegatingHandler _errorReportingHandler = new DelegatingHandler(typeof(WorkspaceDiagnostic).Assembly, "Microsoft.CodeAnalysis.ErrorReporting.FatalError");
1112
private static volatile int _currentUses;
12-
private static Action<Exception> _codeAnalysisErrorHandler;
13-
private static Action<Exception> _errorReportingErrorHandler;
1413

1514
/// <summary>
1615
/// Use this to stop the library exiting the process without telling us.
@@ -23,55 +22,59 @@ internal static class RoslynCrashPreventer
2322
/// See https://github.com/icsharpcode/CodeConverter/issues/521 and https://github.com/icsharpcode/CodeConverter/issues/484
2423
/// There are other ways to find these bugs - just run the expander/reducer on a couple of whole open source projects and the bugs will pile up.
2524
/// </remarks>
26-
public static IDisposable Create(Action<Exception> logError)
25+
public static IDisposable Create(Action<Exception> logErrorToUseIfNotSet)
2726
{
28-
var codeAnalysisAssembly = (typeof(Compilation).Assembly, "Microsoft.CodeAnalysis.FatalError");
29-
var errorReportingAssembly = (typeof(WorkspaceDiagnostic).Assembly, "Microsoft.CodeAnalysis.ErrorReporting.FatalError");
30-
31-
TryExchangeHandler(WrappedCodeAnalysisErrorHandler(logError), codeAnalysisAssembly, ref _codeAnalysisErrorHandler);
32-
TryExchangeHandler(WrappedErrorReportingHandler(logError), errorReportingAssembly, ref _errorReportingErrorHandler);
33-
27+
_codeAnalysisHandler.TryExchangeHandler(logErrorToUseIfNotSet);
28+
_errorReportingHandler.TryExchangeHandler(logErrorToUseIfNotSet);
3429
Interlocked.Increment(ref _currentUses);
3530
return new ActionDisposable(() => Interlocked.Decrement(ref _currentUses));
3631
}
3732

38-
private static void TryExchangeHandler(Action<Exception> logError, (Assembly Assembly, string) handlerContainer, ref Action<Exception> originalHandler)
33+
private class DelegatingHandler
3934
{
40-
if (originalHandler != null || logError == null) return;
41-
lock (_exchangeLock) {
42-
originalHandler ??= ExchangeFatalErrorHandler(logError, handlerContainer);
35+
private readonly Assembly _assembly;
36+
private readonly string _containingType;
37+
private readonly object _exchangeLock = new object();
38+
private Action<Exception> _originalHandler;
39+
40+
public DelegatingHandler(Assembly assembly, string containingType)
41+
{
42+
_assembly = assembly;
43+
_containingType = containingType;
4344
}
44-
}
4545

46-
private static Action<Exception> ExchangeFatalErrorHandler(Action<Exception> errorHandler, (Assembly assembly, string containingType) container)
47-
{
48-
try {
49-
var fataErrorType = container.assembly.GetType(container.containingType);
50-
var fatalHandlerField = fataErrorType.GetField("s_fatalHandler", BindingFlags.NonPublic | BindingFlags.Static);
51-
var originalHandler = (Action<Exception>)fatalHandlerField.GetValue(null);
52-
if (originalHandler != null) {
53-
fatalHandlerField.SetValue(null, errorHandler);
46+
public void TryExchangeHandler(Action<Exception> logError)
47+
{
48+
if (_originalHandler != null || logError == null) return;
49+
lock (_exchangeLock) {
50+
_originalHandler ??= ExchangeFatalErrorHandler(WrappedCodeAnalysisErrorHandler(logError));
5451
}
55-
return originalHandler;
56-
} catch (Exception) {
57-
return null;
5852
}
59-
}
6053

61-
private static Action<Exception> WrappedCodeAnalysisErrorHandler(Action<Exception> errorHandler) => e => {
62-
if (_currentUses > 0) {
63-
errorHandler(e);
64-
} else {
65-
_codeAnalysisErrorHandler(e);
66-
}
67-
};
54+
private Action<Exception> ExchangeFatalErrorHandler(Action<Exception> errorHandler)
55+
{
56+
try {
57+
var fataErrorType = _assembly.GetType(_containingType);
58+
var fatalHandlerField =
59+
fataErrorType.GetField("s_fatalHandler", BindingFlags.NonPublic | BindingFlags.Static);
60+
var originalHandler = (Action<Exception>)fatalHandlerField.GetValue(null);
61+
if (originalHandler != null) {
62+
fatalHandlerField.SetValue(null, errorHandler);
63+
}
6864

69-
private static Action<Exception> WrappedErrorReportingHandler(Action<Exception> errorHandler) => e => {
70-
if (_currentUses > 0) {
71-
errorHandler(e);
72-
} else {
73-
_errorReportingErrorHandler(e);
65+
return originalHandler;
66+
} catch (Exception) {
67+
return null;
68+
}
7469
}
75-
};
70+
71+
private Action<Exception> WrappedCodeAnalysisErrorHandler(Action<Exception> errorHandler) => e => {
72+
if (_currentUses > 0) {
73+
errorHandler(e);
74+
} else {
75+
_originalHandler(e);
76+
}
77+
};
78+
}
7679
}
7780
}

0 commit comments

Comments
 (0)