Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Symbolic execution engine should not throw on TypePattern and RelationalPattern (introduced in .Net 5) #4104

Closed
KraftyKanuck opened this issue Mar 1, 2021 · 4 comments · Fixed by #4189
Labels
Area: C# C# rules related issues. Area: CFG/SE CFG and SE related issues. Type: Bug Exceptions and blocking issues during analysis.
Milestone

Comments

@KraftyKanuck
Copy link

KraftyKanuck commented Mar 1, 2021

Description

When not specifying a discard operator during a case for a switch with a generic type, sonar analyzer throws a SymbolicExecutionRunner

Severity Code Description Project Path File Line Suppression State
Error AD0001 Analyzer 'SonarAnalyzer.Rules.SymbolicExecution.SymbolicExecutionRunner' threw an exception of type 'SonarAnalyzer.SymbolicExecution.SymbolicExecutionException' with message 'Error processing method: Evaluate ## Method file: MyPath\SonarExample.cs ## Method line: 17,8 ## Inner exception: System.NotSupportedException: TypePattern ## at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitInstruction(ExplodedGraphNode node) ## at SonarAnalyzer.SymbolicExecution.AbstractExplodedGraph.Walk() ## at SonarAnalyzer.Rules.SymbolicExecution.SymbolicExecutionRunner.Analyze(CSharpExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) ## at SonarAnalyzer.Extensions.SonarAnalysisContextExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 runAnalysis, SyntaxNodeAnalysisContext context) ## '. MyProject MyPath MyPath\CSC 1 Active

Repro steps

#nullable enable

using System;
using System.Threading.Tasks;

namespace SonarAnalyzerFailure
{
    public class SonarExample
    {
        private IOtherClass otherClass;

        public SonarExample(IOtherClass otherClass)
        {
            this.otherClass = otherClass;
        }

        public async Task<int> Evaluate()
        {
            var result = await this.otherClass.DoSomething();

            switch (result)
            {
                case ClassOne<int> error: // this is fine
                    // some code
                    break;

                case ClassTwo<int>: // this throws a SymbolicExecutionException
                    // some code
                    break;

                case ClassThree<int> _: // this is fine
                    // some code
                    break;

                default:
                    throw new NotImplementedException(nameof(ISomeClass<int>));
            }

            return 42;
        }
    }

    public interface ISomeClass<out T>
        where T : notnull
    {
    }

    public sealed class ClassOne<T> :
        ISomeClass<T>
        where T : notnull
    {
    }

    public sealed class ClassTwo<T> :
        ISomeClass<T>
        where T : notnull
    {
    }

    public sealed class ClassThree<T> :
        ISomeClass<T>
        where T : notnull
    {
    }

    public interface IOtherClass
    {
        Task<ISomeClass<int>> DoSomething();
    }
}

Known workarounds

Change:
case ClassTwo<int>:
to
case ClassTwo<int> _:
or
case ClassTwo<int> foo:

Related information

  • C# 9
  • Visual Studio 2019 - 16.8.3
  • dotnet 5.0
  • occurs in SonarAnalyzer.CSharp 8.17.0.26580 and 8.19.0.28253
  • Win 10
@mrzottel
Copy link

mrzottel commented Mar 9, 2021

This also happens with relational patterns like
var i = 9;
switch (i) {
case > 0:
.
.
.
}

@costin-zaharia-sonarsource costin-zaharia-sonarsource changed the title SymbolicExecutionException thrown in switch statement when processing awaited generic Extend the symbolic execution engine to support TypePattern (introduced in .Net 5) Mar 25, 2021
@costin-zaharia-sonarsource
Copy link
Member

Hi @KraftyKanuck.

This problem appears due to the fact that we don't yet support the TypePattern introduced in .Net 5 (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/patterns3).

As a result the analysis for snippets like:

switch (values)
{
    case IEnumerable<int>: // TypePattern is not supported
        break;
}

is not yet supported.

We will do a first step this sprint to not throw but proper support will be added later this year.

@costin-zaharia-sonarsource costin-zaharia-sonarsource added Area: C# C# rules related issues. Area: C#9 Area: CFG/SE CFG and SE related issues. Type: Bug Exceptions and blocking issues during analysis. labels Mar 25, 2021
@costin-zaharia-sonarsource costin-zaharia-sonarsource changed the title Extend the symbolic execution engine to support TypePattern (introduced in .Net 5) Extend the symbolic execution engine to support TypePattern and RelationalPattern (introduced in .Net 5) Mar 25, 2021
@costin-zaharia-sonarsource
Copy link
Member

Same problem appears for RelationalPattern (dotnet/csharplang#812) too.

switch (i)
{
    case > 0:
        break;
}

@costin-zaharia-sonarsource costin-zaharia-sonarsource changed the title Extend the symbolic execution engine to support TypePattern and RelationalPattern (introduced in .Net 5) Symbolic execution engine should not throw on TypePattern and RelationalPattern (introduced in .Net 5) Mar 25, 2021
@pavel-mikula-sonarsource pavel-mikula-sonarsource added this to the 8.21 milestone Apr 6, 2021
@perlun
Copy link

perlun commented Nov 27, 2021

For the reference, I think I also run into this (or some closely related bug) on the following code. The case "foo" or "bar" is the problem here.

Upgrading to version 8.29.0.36737 helped; at least versions 8.22.0.31243 through 8.28.0.36354 exhibit the bug.

string lexeme = typeReference.TypeSpecifier.Lexeme;

switch (lexeme)
{
    case "int" or "Int32":
        typeReference.ClrType = typeof(int);
        break;

    case "long" or "Int64":
        typeReference.ClrType = typeof(long);
        break;

    case "double" or "Double":
        typeReference.ClrType = typeof(double);
        break;

    case "string" or "String":
        typeReference.ClrType = typeof(string);
        break;

    case "void":
        typeReference.ClrType = typeof(void);
        break;

    // Other types means ClrType will remain `null`; this is then handled elsewhere (in
    // TypesResolvedValidator)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: C# C# rules related issues. Area: CFG/SE CFG and SE related issues. Type: Bug Exceptions and blocking issues during analysis.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants