Skip to content

Commit 269b2b5

Browse files
Do a single field exchange, in case someone else exchanges handlers
1 parent 512ef7c commit 269b2b5

File tree

1 file changed

+42
-18
lines changed

1 file changed

+42
-18
lines changed
Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
using System;
22
using System.Reflection;
3+
using System.Threading;
34
using Microsoft.CodeAnalysis;
45

56
namespace ICSharpCode.CodeConverter.Shared
67
{
78
internal static class RoslynCrashPreventer
89
{
9-
private static object _exchangeLock = new object();
10+
private static readonly object _exchangeLock = new object();
11+
private static volatile int _currentUses;
12+
private static Action<Exception> _codeAnalysisErrorHandler;
13+
private static Action<Exception> _errorReportingErrorHandler;
1014

1115
/// <summary>
1216
/// Use this to stop the library exiting the process without telling us.
@@ -21,33 +25,53 @@ internal static class RoslynCrashPreventer
2125
/// </remarks>
2226
public static IDisposable Create(Action<Exception> logError)
2327
{
24-
var FirstHandlerContainingType = (typeof(Compilation).Assembly, "Microsoft.CodeAnalysis.FatalError");
25-
var SecondHandlerContainingType = (typeof(WorkspaceDiagnostic).Assembly, "Microsoft.CodeAnalysis.ErrorReporting.FatalError");
26-
27-
var codeAnalysisErrorHandler = ExchangeFatalErrorHandler(logError, FirstHandlerContainingType);
28-
var codeAnalysisErrorReportingErrorHandler = ExchangeFatalErrorHandler(logError, SecondHandlerContainingType);
29-
return new ActionDisposable(() => {
30-
ExchangeFatalErrorHandler(codeAnalysisErrorHandler, FirstHandlerContainingType);
31-
ExchangeFatalErrorHandler(codeAnalysisErrorReportingErrorHandler, SecondHandlerContainingType);
32-
});
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+
34+
Interlocked.Increment(ref _currentUses);
35+
return new ActionDisposable(() => Interlocked.Decrement(ref _currentUses));
36+
}
37+
38+
private static void TryExchangeHandler(Action<Exception> logError, (Assembly Assembly, string) handlerContainer, ref Action<Exception> originalHandler)
39+
{
40+
if (originalHandler != null || logError == null) return;
41+
lock (_exchangeLock) {
42+
originalHandler ??= ExchangeFatalErrorHandler(logError, handlerContainer);
43+
}
3344
}
3445

35-
private static Action<Exception> ExchangeFatalErrorHandler(Action<Exception> errorHandler, (Assembly assembly, string containingType) container, Action<Exception> errorHanderToReplace = null)
46+
private static Action<Exception> ExchangeFatalErrorHandler(Action<Exception> errorHandler, (Assembly assembly, string containingType) container)
3647
{
37-
if (errorHandler == null) return null;
3848
try {
3949
var fataErrorType = container.assembly.GetType(container.containingType);
4050
var fatalHandlerField = fataErrorType.GetField("s_fatalHandler", BindingFlags.NonPublic | BindingFlags.Static);
41-
lock (_exchangeLock) {
42-
var originalHandler = (Action<Exception>)fatalHandlerField.GetValue(null);
43-
if (originalHandler != null && errorHanderToReplace == null || originalHandler == errorHanderToReplace) {
44-
fatalHandlerField.SetValue(null, errorHandler);
45-
}
46-
return originalHandler;
51+
var originalHandler = (Action<Exception>)fatalHandlerField.GetValue(null);
52+
if (originalHandler != null) {
53+
fatalHandlerField.SetValue(null, errorHandler);
4754
}
55+
return originalHandler;
4856
} catch (Exception) {
4957
return null;
5058
}
5159
}
60+
61+
private static Action<Exception> WrappedCodeAnalysisErrorHandler(Action<Exception> errorHandler) => e => {
62+
if (_currentUses > 0) {
63+
errorHandler(e);
64+
} else {
65+
_codeAnalysisErrorHandler(e);
66+
}
67+
};
68+
69+
private static Action<Exception> WrappedErrorReportingHandler(Action<Exception> errorHandler) => e => {
70+
if (_currentUses > 0) {
71+
errorHandler(e);
72+
} else {
73+
_errorReportingErrorHandler(e);
74+
}
75+
};
5276
}
5377
}

0 commit comments

Comments
 (0)