Sonar-dotnet: Fix SymbolicExecution error AD0001 for indices and ranges

Created on 25 Feb 2020  路  7Comments  路  Source: SonarSource/sonar-dotnet

Description

I get a long list of AD001 errors on one piece of code in my solution. The error is about the Analyzer itself.

Warning AD0001  Analyzer 'SonarAnalyzer.Rules.CSharp.InvalidCastToInterface' threw an exception of type 'SonarAnalyzer.SymbolicExecution.SymbolicExecutionException' with message 'Error processing method: CreateReport 
Method file: [MyMethodFile] 
Method line: 467,8 
Inner exception: System.InvalidOperationException: This operation does not apply to an empty instance. 
   at System.Collections.Immutable.ImmutableStack`1.Peek() 
   at SonarAnalyzer.SymbolicExecution.ProgramState.PopValue(SymbolicValue& poppedValue) 
   at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitSimpleAssignment(AssignmentExpressionSyntax assignment, ProgramState programState) 
   at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitInstruction(ExplodedGraphNode node) 
   at SonarAnalyzer.SymbolicExecution.AbstractExplodedGraph.Walk() 
   at SonarAnalyzer.Rules.CSharp.InvalidCastToInterface.<>c.<Initialize>b__8_1(CSharpExplodedGraph e, SyntaxNodeAnalysisContext c) 
   at SonarAnalyzer.SymbolicExecution.FlowAnalysisExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 analyze, SyntaxNodeAnalysisContext context) 
'.  [MySymbol]  1   Active

Also
InvalidCastToInterface
NullPointerDerefernce
EmptyNullValueAccess
ObjectsShouldNotBeDisposedMoreThanOnce
ConditionEvaluatesToConstant
EmptyCollectionsShouldNotBeEnumerated
etc, etc

All these errors are pointing to the first few lines of the code, mostly about the second line of this code (method line 468,8)

 private static async Task<WordDocument> CreateReport(int dtoId, string userId, string requestingUserId, string ipAddress, 
            string reportName, string normGroupName, TblLogExaminer7513.EnumAccessType typeDoc, string reason)
        {

            List<TblSessions> tblSessions = await TblSessions.FindTestsById(dtoId);
            if (tblSessions == null) return null;

....

Repro steps

No idea, it happens in about one particular method. It is consistent shown in the Warnings

Actual behavior

I did a clean of the solution, then a rebuild. 9 of these errors appear immediately (less then before the rebuild)

Known workarounds

Please provide a description of any known workarounds.
none

Related information

SonarLint for Visual Studio 2019 Version: 4.18.0.15344 (extension)
Visual Studio Version : 2019 16.4.5 with Resharper 2019.3.3
SonarQube server version: Not used
Languages in your solution: C#, JavaScript

C# CFG Bug

All 7 comments

thanks @vankampenp for the repro!

Would it be possible to share the full CreateReport method (or maybe extract a minimal reproducer out of it)?

With what you've gave me I cannot do a reproducer. This is what I tried:

namespace Reproducers
{
    using System.Net.Http;
    using System.Threading.Tasks;
    public class Repro3162
    {
        private static readonly HttpClient client = new HttpClient();
        private static async Task<string> CreateReport()
        {

            HttpResponseMessage response = await client.GetAsync("http://www.contoso.com/");
            if (response == null) return null;
            return null;
        }
    }
}

In the exception message, was there something more than just 'Error processing method: CreateReport ?

Basically, to do a reproducer we need the full method to be able to construct the Control Flow Graph of the full method and then run the Symbolic Execution engine on it.

I am also getting a long list of AD0001 errors for one class.

Severity    Code    Description Project File    Line    Suppression State   Detail Description
Warning AD0001  Analyzer 'SonarAnalyzer.Rules.CSharp.ObjectsShouldNotBeDisposedMoreThanOnce' threw an exception of type 'SonarAnalyzer.SymbolicExecution.SymbolicExecutionException' with message 'Error processing method: RegisterAppServices ## Method file: C:\MySystem\MyProject\AppStartup\Swagger\SwaggerServiceRegistration.cs ## Method line: 40,8 ## Inner exception: System.InvalidOperationException: This operation does not apply to an empty instance. ##    at System.Collections.Immutable.ImmutableStack`1.Peek() ##    at SonarAnalyzer.SymbolicExecution.ProgramState.PopValue(SymbolicValue& poppedValue) ##    at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitSimpleAssignment(AssignmentExpressionSyntax assignment, ProgramState programState) ##    at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitInstruction(ExplodedGraphNode node) ##    at SonarAnalyzer.SymbolicExecution.AbstractExplodedGraph.Walk() ##    at SonarAnalyzer.Rules.CSharp.ObjectsShouldNotBeDisposedMoreThanOnce.CheckForMultipleDispose(CSharpExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) ##    at SonarAnalyzer.SymbolicExecution.FlowAnalysisExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 analyze, SyntaxNodeAnalysisContext context) ## '.   MyProject       1   Active  Analyzer 'SonarAnalyzer.Rules.CSharp.ObjectsShouldNotBeDisposedMoreThanOnce' threw the following exception:
'Exception occurred with following context:
Compilation: MyProject
SyntaxTree: C:\MySystem\MyProject\AppStartup\Swagger\SwaggerServiceRegistration.cs
SyntaxNode: public void RegisterAppServices ... [MethodDeclarationSyntax]@[1464..2193) (39,8)-(52,9)

SonarAnalyzer.SymbolicExecution.SymbolicExecutionException: Error processing method: RegisterAppServices ## Method file: C:\MySystem\MyProject\AppStartup\Swagger\SwaggerServiceRegistration.cs ## Method line: 40,8 ## Inner exception: System.InvalidOperationException: This operation does not apply to an empty instance. ##    at System.Collections.Immutable.ImmutableStack`1.Peek() ##    at SonarAnalyzer.SymbolicExecution.ProgramState.PopValue(SymbolicValue& poppedValue) ##    at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitSimpleAssignment(AssignmentExpressionSyntax assignment, ProgramState programState) ##    at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitInstruction(ExplodedGraphNode node) ##    at SonarAnalyzer.SymbolicExecution.AbstractExplodedGraph.Walk() ##    at SonarAnalyzer.Rules.CSharp.ObjectsShouldNotBeDisposedMoreThanOnce.CheckForMultipleDispose(CSharpExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context) ##    at SonarAnalyzer.SymbolicExecution.FlowAnalysisExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 analyze, SyntaxNodeAnalysisContext context) ##  ---> System.InvalidOperationException: This operation does not apply to an empty instance.
   at System.Collections.Immutable.ImmutableStack`1.Peek()
   at SonarAnalyzer.SymbolicExecution.ProgramState.PopValue(SymbolicValue& poppedValue)
   at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitSimpleAssignment(AssignmentExpressionSyntax assignment, ProgramState programState)
   at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitInstruction(ExplodedGraphNode node)
   at SonarAnalyzer.SymbolicExecution.AbstractExplodedGraph.Walk()
   at SonarAnalyzer.Rules.CSharp.ObjectsShouldNotBeDisposedMoreThanOnce.CheckForMultipleDispose(CSharpExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context)
   at SonarAnalyzer.SymbolicExecution.FlowAnalysisExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 analyze, SyntaxNodeAnalysisContext context)
   --- End of inner exception stack trace ---
   at SonarAnalyzer.SymbolicExecution.FlowAnalysisExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 analyze, SyntaxNodeAnalysisContext context)
   at SonarAnalyzer.SymbolicExecution.FlowAnalysisExtensions.<>c__DisplayClass0_0.<RegisterExplodedGraphBasedAnalysis>b__0(SyntaxNodeAnalysisContext c)
   at SonarAnalyzer.Helpers.DiagnosticAnalyzerContextHelper.<>c__DisplayClass0_0`1.<RegisterSyntaxNodeActionInNonGenerated>b__0(SyntaxNodeAnalysisContext c)
   at SonarAnalyzer.Helpers.SonarAnalysisContext.<>c__DisplayClass30_0`1.<RegisterContextAction>b__0(TContext c)
   at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.<>c__55`1.<ExecuteSyntaxNodeAction>b__55_0(ValueTuple`2 data)
   at Microsoft.CodeAnalysis.Diagnostics.AnalyzerExecutor.ExecuteAndCatchIfThrows_NoLock[TArg](DiagnosticAnalyzer analyzer, Action`1 analyze, TArg argument, Nullable`1 info)
-----
System.InvalidOperationException: This operation does not apply to an empty instance.
   at System.Collections.Immutable.ImmutableStack`1.Peek()
   at SonarAnalyzer.SymbolicExecution.ProgramState.PopValue(SymbolicValue& poppedValue)
   at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitSimpleAssignment(AssignmentExpressionSyntax assignment, ProgramState programState)
   at SonarAnalyzer.SymbolicExecution.CSharpExplodedGraph.VisitInstruction(ExplodedGraphNode node)
   at SonarAnalyzer.SymbolicExecution.AbstractExplodedGraph.Walk()
   at SonarAnalyzer.Rules.CSharp.ObjectsShouldNotBeDisposedMoreThanOnce.CheckForMultipleDispose(CSharpExplodedGraph explodedGraph, SyntaxNodeAnalysisContext context)
   at SonarAnalyzer.SymbolicExecution.FlowAnalysisExtensions.Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action`2 analyze, SyntaxNodeAnalysisContext context)
-----
'.

The class that is causing the issue is



namespace MyProject.AppStartup.Swagger
{
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.OpenApi.Models;
    using Swashbuckle.AspNetCore.Filters;
    using System;
    using System.IO;
    using System.Linq;
    using System.Reflection;

    /// <summary>
    /// Register Swagger - Swashbuckle's swagger (OpenAPI 3.0) generation
    /// </summary>
    /// <seealso cref="MyProject.AppStartup.IServiceRegistration" />
    public class SwaggerServiceRegistration : IServiceRegistration
    {
        /// <summary>
        /// The XML docs paths.
        /// </summary>
        private static string[] XmlDocsPaths
        {
            get
            {
                var currentAssembly = Assembly.GetExecutingAssembly();
                var xmlDocs = currentAssembly.GetReferencedAssemblies()
                .Union(new AssemblyName[] { currentAssembly.GetName() })
                .Select(a => Path.Combine(Path.GetDirectoryName(currentAssembly.Location), $"{a.Name}.xml"))
                .Where(f => File.Exists(f)).ToArray();

                return xmlDocs;
            }
        }

        /// <summary>
        /// Registers application services.
        /// </summary>
        /// <param name="services">The application's service collection.</param>
        /// <param name="configuration">The application's configuration file.</param>
        public void RegisterAppServices(IServiceCollection services, IConfiguration configuration)
        {
            var apiContactDetails = configuration.GetSection("APIContactDetails").Get<ApiContactDetails>();
            if (apiContactDetails != null)
            {
                SwaggerConfig.Settings.APIContact = new OpenApiContact
                {
                    Name = apiContactDetails.Name,
                    Email = apiContactDetails.Email,
                    Url = string.IsNullOrWhiteSpace(apiContactDetails.Website) ? null : new Uri(apiContactDetails.Website)
                };
            }

            CommonUtilities.Swagger.SwaggerServiceRegistration.Register(services, SwaggerConfig.Settings, XmlDocsPaths);

            services.AddSwaggerExamplesFromAssemblyOf<Startup>();
        }
    }
}

The error occurs 8 times.
Interestingly enough I have inherited the IServiceRegistration in a number of classes with implementing the public void RegisterAppServices(IServiceCollection services, IConfiguration configuration) method and there are no problems with those classes.
I also tried emptying out the method in this class to see if the errors would go away, but they didn't.

thanks @vankampenp for the repro!

Would it be possible to share the full CreateReport method (or maybe extract a minimal reproducer out of it)?

Thanks Andrei,
the repo below shows the issue at my end. I removed lots of the CreateReport code. The code does not make sense as it is now, but it does show the issue (6 times) in the CreateReport method.

SonarIssue.zip

For reference: this is the condensed CreateReport method in the repo:

 private static async Task<WordDocument> CreateReport(int dtoId, string userId, string requestingUserId,
            string ipAddress, string reportName, string normGroupName, EnumAccessType typeDoc, string reason = null)
        {
            List<TblSessions> tblSessions = await TblSessions.FindTestsById(dtoId, userId, requestingUserId, ipAddress, reportName, normGroupName, typeDoc, reason);
            if (tblSessions == null) return null;
            var testId = tblSessions[0].TestId;

            List<TblSessions> tblSessionRetest =  TblSessions.FindRetest(dtoId, userId); //get the older sessions (excluding the current)
            if (tblSessionRetest.Count > 1)
                tblSessionRetest = testId.ToLower() == "zmlab"
                    ? tblSessionRetest.OrderByDescending(s => s.DtoId).Take(3).ToList() //last three sessions 
                    : new List<TblSessions> { tblSessionRetest[0], tblSessionRetest[^1] }; //first and last
            //get the scores and norm for the current report

            return new WordDocument();

        }

thanks @vankampenp for the reproducers project!

Here's the smallest reproducer I can get. Collection initializer with ^1 index member.

public string[] DoSomething(string[] list)
{
    return new[] { list[^1] };
}

@pavel-mikula-sonarsource that means the repro from @SylviaJ would have a different root cause?

@andrei-epure-sonarsource I'm unable to reproduce it based on @SylviaJ example.

It either does not work with my mock up setup or the root cause is actually outside this file.

@SylviaJ, can you please try to provide standalone reproducible scenario (mini project) or minimal reproducible scenario for your case? Thank you

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Khaos66 picture Khaos66  路  3Comments

bitbonk picture bitbonk  路  3Comments

valhristov picture valhristov  路  3Comments

duncanp-sonar picture duncanp-sonar  路  5Comments

pavel-mikula-sonarsource picture pavel-mikula-sonarsource  路  3Comments