提交 43f3499a 编写于 作者: M Manish Vasani 提交者: GitHub

Protect against analyzers registering async callback that can crash VS (#13140)

We have seen two big analyzer packages (CodeCracker and RefactoringEssentials) end up with registering async actions, which can crash VS from the async continuations.
See [this](https://github.com/code-cracker/code-cracker/issues/375#issue-87474837) for more details. Now we prevent this by disallowing analyzers to register async callbacks.

Fixes https://github.com/dotnet/roslyn/issues/13120
上级 0d9a60cf
......@@ -915,6 +915,36 @@ public void TestReportingDiagnosticWithInvalidLocation()
}
}
[Fact, WorkItem(13120, "https://github.com/dotnet/roslyn/issues/13120")]
public void TestRegisteringAsyncAnalyzerMethod()
{
string source = @"";
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerWithAsyncMethodRegistration() };
string message = new ArgumentException(string.Format(CodeAnalysisResources.AsyncAnalyzerActionCannotBeRegistered), "action").Message;
CreateCompilationWithMscorlib45(source)
.VerifyDiagnostics()
.VerifyAnalyzerDiagnostics(analyzers, null, null, logAnalyzerExceptionAsDiagnostics: true,
expected: Diagnostic("AD0001")
.WithArguments("Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers+AnalyzerWithAsyncMethodRegistration", "System.ArgumentException", message)
.WithLocation(1, 1));
}
[Fact, WorkItem(13120, "https://github.com/dotnet/roslyn/issues/13120")]
public void TestRegisteringAsyncAnalyzerLambda()
{
string source = @"";
var analyzers = new DiagnosticAnalyzer[] { new AnalyzerWithAsyncLambdaRegistration() };
string message = new ArgumentException(string.Format(CodeAnalysisResources.AsyncAnalyzerActionCannotBeRegistered), "action").Message;
CreateCompilationWithMscorlib45(source)
.VerifyDiagnostics()
.VerifyAnalyzerDiagnostics(analyzers, null, null, logAnalyzerExceptionAsDiagnostics: true,
expected: Diagnostic("AD0001")
.WithArguments("Microsoft.CodeAnalysis.CommonDiagnosticAnalyzers+AnalyzerWithAsyncLambdaRegistration", "System.ArgumentException", message)
.WithLocation(1, 1));
}
[Fact, WorkItem(1473, "https://github.com/dotnet/roslyn/issues/1473")]
public void TestReportingNotConfigurableDiagnostic()
{
......
......@@ -188,6 +188,15 @@ internal class CodeAnalysisResources {
}
}
/// <summary>
/// Looks up a localized string similar to Analyzer attempted to register an &apos;async&apos; action, which is not supported..
/// </summary>
internal static string AsyncAnalyzerActionCannotBeRegistered {
get {
return ResourceManager.GetString("AsyncAnalyzerActionCannotBeRegistered", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Can&apos;t alias a module..
/// </summary>
......
......@@ -419,6 +419,9 @@
<data name="ArgumentElementCannotBeNull" xml:space="preserve">
<value>Argument cannot have a null element.</value>
</data>
<data name="AsyncAnalyzerActionCannotBeRegistered" xml:space="preserve">
<value>Analyzer attempted to register an 'async' action, which is not supported.</value>
</data>
<data name="UnsupportedDiagnosticReported" xml:space="preserve">
<value>Reported diagnostic with ID '{0}' is not supported by the analyzer.</value>
</data>
......
......@@ -2,6 +2,8 @@
using System;
using System.Collections.Immutable;
using System.Reflection;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Diagnostics
......@@ -94,6 +96,12 @@ private static void VerifyAction<TContext>(Action<TContext> action)
{
throw new ArgumentNullException(nameof(action));
}
// Disallow async methods to be registered.
if (action.GetMethodInfo().IsDefined(typeof(AsyncStateMachineAttribute)))
{
throw new ArgumentException(CodeAnalysisResources.AsyncAnalyzerActionCannotBeRegistered, nameof(action));
}
}
private static void VerifySymbolKinds(ImmutableArray<SymbolKind> symbolKinds)
......
......@@ -5,6 +5,7 @@
using System.Collections.Immutable;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
......@@ -502,6 +503,52 @@ public override void Initialize(AnalysisContext context)
}
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AnalyzerWithAsyncMethodRegistration : DiagnosticAnalyzer
{
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
"ID",
"Title1",
"Message1",
"Category1",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationAction(AsyncAction);
}
private async void AsyncAction(CompilationAnalysisContext context)
{
context.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.None));
await Task.FromResult(true);
}
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AnalyzerWithAsyncLambdaRegistration : DiagnosticAnalyzer
{
public static readonly DiagnosticDescriptor Descriptor = new DiagnosticDescriptor(
"ID",
"Title1",
"Message1",
"Category1",
defaultSeverity: DiagnosticSeverity.Warning,
isEnabledByDefault: true);
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(Descriptor);
public override void Initialize(AnalysisContext context)
{
context.RegisterCompilationAction(async (compilationContext) =>
{
compilationContext.ReportDiagnostic(Diagnostic.Create(Descriptor, Location.None));
await Task.FromResult(true);
});
}
}
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class AnalyzerThatThrowsInGetMessage : DiagnosticAnalyzer
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册