未验证 提交 ceea0803 编写于 作者: R Rikki Gibson 提交者: GitHub

Fix stack overflow where overload resolution gets parameter type attributes (#33498)

* Add reproducer for #33388

* Skip normalizing task types if binding attribute arguments

* Use InAttributeArgument property

* Add test where task-like normalization affects overload resolution

* Update AttributeArgument_TaskLikeOverloadResolution test case

* Add assert and remove apparently unused branch

* Add back comparison of remaining parameter types with InAttributeArgument guard

* Update comment on remaining parameter comparisons

* Add comment describing why we don't normalize task types in attribute arguments
上级 8ea5ae39
......@@ -1559,8 +1559,17 @@ private static ParameterSymbol GetParameter(int argIndex, MemberAnalysisResult r
ref useSiteDiagnostics,
out okToDowngradeToNeither);
var type1Normalized = type1.NormalizeTaskTypes(Compilation);
var type2Normalized = type2.NormalizeTaskTypes(Compilation);
var type1Normalized = type1;
var type2Normalized = type2;
// Normalizing task types can cause attributes to be bound on the type,
// and attribute arguments may call overloaded methods in error cases.
// To avoid a stack overflow, we must not normalize task types within attribute arguments.
if (!_binder.InAttributeArgument)
{
type1Normalized = type1.NormalizeTaskTypes(Compilation);
type2Normalized = type2.NormalizeTaskTypes(Compilation);
}
if (r == BetterResult.Neither)
{
......@@ -1656,6 +1665,8 @@ private static ParameterSymbol GetParameter(int argIndex, MemberAnalysisResult r
// We might have got out of the loop above early and allSame isn't completely calculated.
// We need to ensure that we are not going to skip over the next 'if' because of that.
// One way we can break out of the above loop early is when the corresponding method parameters have identical types
// but different ref kinds. See RefOmittedComCall_OverloadResolution_MultipleArguments_ErrorCases for an example.
if (allSame && m1ParametersUsedIncludingExpansionAndOptional == m2ParametersUsedIncludingExpansionAndOptional)
{
// Complete comparison for the remaining parameter types
......@@ -1674,11 +1685,17 @@ private static ParameterSymbol GetParameter(int argIndex, MemberAnalysisResult r
var parameter1 = GetParameter(i, m1.Result, m1LeastOverridenParameters);
var type1 = GetParameterType(parameter1, m1.Result);
var type1Normalized = type1.NormalizeTaskTypes(Compilation);
var parameter2 = GetParameter(i, m2.Result, m2LeastOverridenParameters);
var type2 = GetParameterType(parameter2, m2.Result);
var type2Normalized = type2.NormalizeTaskTypes(Compilation);
var type1Normalized = type1;
var type2Normalized = type2;
if (!_binder.InAttributeArgument)
{
type1Normalized = type1.NormalizeTaskTypes(Compilation);
type2Normalized = type2.NormalizeTaskTypes(Compilation);
}
if (Conversions.ClassifyImplicitConversionFromType(type1Normalized, type2Normalized, ref useSiteDiagnostics).Kind != ConversionKind.Identity)
{
......
......@@ -8980,6 +8980,40 @@ public static async Task UserInfo()
Diagnostic(ErrorCode.ERR_BadAttributeParamType, "Command").WithArguments("Fx", "a.Class1.CommandAttribute.FxCommand").WithLocation(22, 4));
}
[Fact, WorkItem(33388, "https://github.com/dotnet/roslyn/issues/33388")]
public void AttributeCrashRepro_33388()
{
string source = @"
using System;
public static class C
{
public static int M(object obj) => 42;
public static int M(C2 c2) => 42;
}
public class RecAttribute : Attribute
{
public RecAttribute(int i)
{
this.i = i;
}
private int i;
}
[Rec(C.M(null))]
public class C2
{
}
";
var comp = CreateCompilation(source);
comp.VerifyDiagnostics(
// (20,6): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [Rec(C.M(null))]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "C.M(null)").WithLocation(20, 6));
}
#endregion
}
}
......@@ -1320,5 +1320,61 @@ static void Main()
// await new MyTask();
Diagnostic(ErrorCode.ERR_GenericConstraintNotSatisfiedRefType, "await new MyTask();").WithArguments("MyTaskMethodBuilder.AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter, ref TStateMachine)", "IMyAwaiter", "TAwaiter", "MyTask.Awaiter").WithLocation(5, 9));
}
[Fact, WorkItem(33388, "https://github.com/dotnet/roslyn/pull/33388")]
public void AttributeArgument_TaskLikeOverloadResolution()
{
var source = @"
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
class A : Attribute
{
public A(int i) { }
}
class B
{
public static int F(Func<MyTask<C>> t) => 1;
public static int F(Func<Task<object>> t) => 2;
}
[A(B.F(async () => null))]
class C
{
}
[AsyncMethodBuilder(typeof(MyTaskMethodBuilder<>))]
class MyTask<T>
{
internal Awaiter GetAwaiter() => null;
internal class Awaiter : INotifyCompletion
{
public void OnCompleted(Action a) { }
internal bool IsCompleted => true;
internal T GetResult() => default(T);
}
}
class MyTaskMethodBuilder<T>
{
public static MyTaskMethodBuilder<T> Create() => null;
public void SetStateMachine(IAsyncStateMachine stateMachine) { }
public void Start<TStateMachine>(ref TStateMachine stateMachine) where TStateMachine : IAsyncStateMachine { }
public void SetException(Exception e) { }
public void SetResult(T t) { }
public void AwaitOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : INotifyCompletion where TStateMachine : IAsyncStateMachine { }
public void AwaitUnsafeOnCompleted<TAwaiter, TStateMachine>(ref TAwaiter awaiter, ref TStateMachine stateMachine) where TAwaiter : ICriticalNotifyCompletion where TStateMachine : IAsyncStateMachine { }
public MyTask<T> Task => default(MyTask<T>);
}
namespace System.Runtime.CompilerServices { class AsyncMethodBuilderAttribute : System.Attribute { public AsyncMethodBuilderAttribute(System.Type t) { } } }
";
var compilation = CreateCompilation(source);
compilation.VerifyDiagnostics(
// (15,4): error CS0182: An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type
// [A(B.F(async () => null))]
Diagnostic(ErrorCode.ERR_BadAttributeArgument, "B.F(async () => null)").WithLocation(15, 4));
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册