private void WriteUCFG <TDeclarationSyntax>(SyntaxNodeAnalysisContext context, Func <TDeclarationSyntax, CSharpSyntaxNode> getBody) where TDeclarationSyntax : SyntaxNode { var declaration = (TDeclarationSyntax)context.Node; var symbol = context.SemanticModel.GetDeclaredSymbol(declaration); var methodSymbol = (symbol is IPropertySymbol propertySymbol) ? propertySymbol.GetMethod // We are in PropertyDeclarationSyntax : symbol as IMethodSymbol; // all other are methods if (methodSymbol == null || methodSymbol.IsAbstract || methodSymbol.IsExtern || !CSharpControlFlowGraph.TryGet(getBody(declaration), context.SemanticModel, out var cfg)) { return; } var ucfg = new UniversalControlFlowGraphBuilder() .Build(context.SemanticModel, declaration, methodSymbol, cfg); if (!IsValid(ucfg)) { return; } var path = Path.Combine(protobufDirectory, $"ucfg_{projectBuildId}_{Interlocked.Increment(ref protobufFileIndex)}.pb"); using (var stream = File.Create(path)) { ucfg.WriteTo(stream); } }
private static void ReportOnDeadParametersAtEntry(MethodContext declaration, IImmutableList <IParameterSymbol> noReportOnParameters) { var bodyNode = (CSharpSyntaxNode)declaration.Body ?? declaration.ExpressionBody; if (bodyNode == null || declaration.Context.Node.IsKind(SyntaxKind.ConstructorDeclaration)) { return; } var excludedParameters = noReportOnParameters; if (declaration.Symbol.IsExtensionMethod) { excludedParameters = excludedParameters.Add(declaration.Symbol.Parameters.First()); } excludedParameters = excludedParameters.AddRange(declaration.Symbol.Parameters.Where(p => p.RefKind != RefKind.None)); var candidateParameters = declaration.Symbol.Parameters.Except(excludedParameters); if (!candidateParameters.Any()) { return; } if (CSharpControlFlowGraph.TryGet(bodyNode, declaration.Context.SemanticModel, out var cfg)) { var lva = CSharpLiveVariableAnalysis.Analyze(cfg, declaration.Symbol, declaration.Context.SemanticModel); var liveParameters = lva.GetLiveIn(cfg.EntryBlock).OfType <IParameterSymbol>(); ReportOnUnusedParameters(declaration, candidateParameters.Except(liveParameters).Except(lva.CapturedVariables), MessageDead, isRemovable: false); } }
public void ExportFunction(MethodDeclarationSyntax method) { if (method.Body == null) { return; } if (IsTooComplexForMlirOrTheCfg(method)) { writer.WriteLine($"// Skipping function {method.Identifier.ValueText}{GetAnonymousArgumentsString(method)}, it contains poisonous unsupported syntaxes"); writer.WriteLine(); return; } blockCounter = 0; blockMap.Clear(); opCounter = 0; opMap.Clear(); var returnType = HasNoReturn(method) ? "()" : MlirType(method.ReturnType); writer.WriteLine($"func @{GetMangling(method)}{GetAnonymousArgumentsString(method)} -> {returnType} {GetLocation(method)} {{"); CreateEntryBlock(method); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); foreach (var block in cfg.Blocks) { ExportBlock(block, method, returnType); } writer.WriteLine("}"); }
public void ExplodedGraph_SequentialInput_Max() { var inputBuilder = new StringBuilder(); for (var i = 0; i < CSharpExplodedGraph.MaxStepCount / 2 + 1; i++) { inputBuilder.AppendLine($"var x{i} = true;"); } var testInput = inputBuilder.ToString(); var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out var semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var maxStepCountReached = false; explodedGraph.MaxStepCountReached += (sender, args) => { maxStepCountReached = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; explodedGraph.Walk(); explorationEnded.Should().BeFalse(); maxStepCountReached.Should().BeTrue(); numberOfExitBlockReached.Should().Be(0); }
public void ExplodedGraph_LoopExploration() { var testInput = "var i = 0; while (i < 1) { i = i + 1; }"; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out var semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var exceeded = 0; explodedGraph.ProgramPointVisitCountExceedLimit += (sender, args) => { exceeded++; args.ProgramPoint.Block.Instructions.Should().Contain(i => i.ToString() == "i < 1"); }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); exceeded.Should().Be(1); }
public void ExplodedGraph_BothBranchesVisited_NonCondition() { var testInput = "var str = this?.ToString();"; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out var semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var countConditionEvaluated = 0; explodedGraph.ConditionEvaluated += (sender, args) => { countConditionEvaluated++; }; var visitedBlocks = new HashSet <Block>(); explodedGraph.InstructionProcessed += (sender, args) => { visitedBlocks.Add(args.ProgramPoint.Block); }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); visitedBlocks.Count.Should().Be(cfg.Blocks.Count() - 1 /* Exit block */); countConditionEvaluated.Should().Be(0); }
private void ProcessLocalFunction(SyntaxNode instruction, HashSet <ISymbol> assignedInBlock, HashSet <ISymbol> usedBeforeAssigned, HashSet <ISymbol> processedLocalFunctions) { var symbol = semanticModel.GetSymbolInfo(((InvocationExpressionSyntax)instruction).Expression).Symbol; // Local function invocation if (symbol != null && (processedLocalFunctions == null || !processedLocalFunctions.Contains(symbol)) && symbol.ContainingSymbol is IMethodSymbol && symbol.DeclaringSyntaxReferences.Length == 1 && symbol.DeclaringSyntaxReferences.Single().GetSyntax() is CSharpSyntaxNode node && node.Kind() == SyntaxKindEx.LocalFunctionStatement && (LocalFunctionStatementSyntaxWrapper)node is LocalFunctionStatementSyntaxWrapper function && CSharpControlFlowGraph.TryGet(function.Body ?? function.ExpressionBody as CSharpSyntaxNode, semanticModel, out var cfg)) { processedLocalFunctions = processedLocalFunctions ?? new HashSet <ISymbol>(); processedLocalFunctions.Add(symbol); foreach (var block in cfg.Blocks.Reverse()) { ProcessBlockInternal(block, processedLocalFunctions, out var subAssigned, out var subUsed); assignedInBlock.UnionWith(subAssigned); usedBeforeAssigned.UnionWith(subUsed); } } }
private static void Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action <CSharpExplodedGraph, SyntaxNodeAnalysisContext> analyze, SyntaxNodeAnalysisContext context) { if (declarationBody == null || declarationBody.ContainsDiagnostics) { return; } if (!CSharpControlFlowGraph.TryGet(declarationBody, context.SemanticModel, out var cfg)) { return; } var lva = CSharpLiveVariableAnalysis.Analyze(cfg, symbol, context.SemanticModel); try { var explodedGraph = new CSharpExplodedGraph(cfg, symbol, context.SemanticModel, lva); analyze(explodedGraph, context); } catch (Exception e) { // Roslyn/MSBuild is currently cutting exception message at the end of the line instead // of displaying the full message. As a workaround, we replace the line ending with ' ## '. // See https://github.com/dotnet/roslyn/issues/1455 and https://github.com/dotnet/roslyn/issues/24346 var sb = new StringBuilder(); sb.AppendLine($"Error processing method: {symbol?.Name ?? "{unknown}"}"); sb.AppendLine($"Method file: {declarationBody.GetLocation()?.GetLineSpan().Path ?? "{unknown}"}"); sb.AppendLine($"Method line: {declarationBody.GetLocation()?.GetLineSpan().StartLinePosition.ToString() ?? "{unknown}"}"); sb.AppendLine($"Inner exception: {e.ToString()}"); throw new SymbolicExecutionException(sb.ToString().Replace(Environment.NewLine, " ## "), e); } }
private void WriteUCFG <TDeclarationSyntax>(SyntaxNodeAnalysisContext context, Func <TDeclarationSyntax, CSharpSyntaxNode> getBody) where TDeclarationSyntax : SyntaxNode { var declaration = (TDeclarationSyntax)context.Node; var symbol = context.SemanticModel.GetDeclaredSymbol(declaration); var methodSymbol = (symbol is IPropertySymbol propertySymbol) ? propertySymbol.GetMethod // We are in PropertyDeclarationSyntax : symbol as IMethodSymbol; // all other are methods if (methodSymbol == null || methodSymbol.IsAbstract || methodSymbol.IsExtern || !CSharpControlFlowGraph.TryGet(getBody(declaration), context.SemanticModel, out var cfg)) { return; } var ucfg = new UniversalControlFlowGraphBuilder() .Build(context.SemanticModel, declaration, methodSymbol, cfg); if (IsValid(ucfg)) { var fileName = $"{projectBuildId}_{Interlocked.Increment(ref protobufFileIndex)}"; WriteProtobuf(ucfg, Path.Combine(protobufDirectory, $"ucfg_{fileName}.pb")); if (ShouldGenerateDot) { WriteDot(Path.Combine(protobufDirectory, $"ucfg_{fileName}.dot"), writer => UcfgSerializer.Serialize(ucfg, writer)); WriteDot(Path.Combine(protobufDirectory, $"cfg_{fileName}.dot"), writer => CfgSerializer.Serialize(ucfg.MethodId, cfg, writer)); } } }
protected UCFG GetUcfgForMethod(string code, string methodName) { (var method, var semanticModel) = TestHelper.Compile(code, Verifier.SystemWebMvcAssembly).GetMethod(methodName); var builder = new UniversalControlFlowGraphBuilder(); return(builder.Build(semanticModel, method, semanticModel.GetDeclaredSymbol(method), CSharpControlFlowGraph.Create(method.Body, semanticModel))); }
public void ExplodedGraph_SingleBranchVisited_If() { string testInput = "var a = false; bool b; if (a) { b = true; } else { b = false; } a = b;"; SemanticModel semanticModel; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfLastInstructionVisits = 0; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = false") { args.ProgramState.GetSymbolValue(aSymbol).Should().Be(SymbolicValue.False); } if (args.Instruction.ToString() == "b = true") { Execute.Assertion.FailWith("We should never get into this branch"); } if (args.Instruction.ToString() == "b = false") { args.ProgramState.GetSymbolValue(bSymbol).Should().Be(SymbolicValue.False); args.ProgramState.GetSymbolValue(aSymbol) .Should().BeNull("a is dead, so there should be no associated value to it."); } if (args.Instruction.ToString() == "a = b") { numberOfLastInstructionVisits++; } }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); numberOfProcessedInstructions.Should().Be(8); numberOfExitBlockReached.Should().Be(1); numberOfLastInstructionVisits.Should().Be(1); }
private static void CheckForNoExitMethod(SyntaxNodeAnalysisContext c, CSharpSyntaxNode body, SyntaxToken identifier) { var symbol = c.SemanticModel.GetDeclaredSymbol(c.Node); if (symbol != null && body != null && CSharpControlFlowGraph.TryGet(body, c.SemanticModel, out var cfg)) { var walker = new CfgWalkerForMethod(new RecursionAnalysisContext(cfg, symbol, identifier.GetLocation(), c)); walker.CheckPaths(); CheckInfiniteJumpLoop(body, cfg, "method", c); } }
public void ExplodedGraph_SequentialInput() { string testInput = "var a = true; var b = false; b = !b; a = (b);"; SemanticModel semanticModel; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var bSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "b")); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = true") { args.ProgramState.GetSymbolValue(aSymbol).Should().Be(SymbolicValue.True); } if (args.Instruction.ToString() == "b = false") { args.ProgramState.GetSymbolValue(bSymbol).Should().Be(SymbolicValue.False); } if (args.Instruction.ToString() == "b = !b") { args.ProgramState.GetSymbolValue(bSymbol).Should().NotBe(SymbolicValue.False); args.ProgramState.GetSymbolValue(bSymbol).Should().NotBe(SymbolicValue.True); } if (args.Instruction.ToString() == "a = (b)") { args.ProgramState.GetSymbolValue(bSymbol) .Should().Be(args.ProgramState.GetSymbolValue(aSymbol)); } }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); numberOfProcessedInstructions.Should().Be(9); numberOfExitBlockReached.Should().Be(1); }
private static UCFG BuildUcfg(CSharpSyntaxNode cfgStartNode, CSharpSyntaxNode ucfgStartNode, IMethodSymbol methodSymbol, SemanticModel semanticModel) { var builder = new UcfgFactory(semanticModel); var cfg = CSharpControlFlowGraph.Create(cfgStartNode, semanticModel); var ucfg = builder.Create(ucfgStartNode, methodSymbol, cfg); //var serializedCfg = CfgSerializer.Serialize(methodName, cfg); //var serializedUcfg = UcfgSerializer.Serialize(ucfg); return(ucfg); }
private ExplodedGraphContext(MethodDeclarationSyntax mainMethod, SemanticModel semanticModel) { this.MainMethod = mainMethod; this.SemanticModel = semanticModel; this.MainMethodSymbol = semanticModel.GetDeclaredSymbol(this.MainMethod) as IMethodSymbol; this.ControlFlowGraph = CSharpControlFlowGraph.Create(this.MainMethod.Body, semanticModel); this.LiveVariableAnalysis = CSharpLiveVariableAnalysis.Analyze(this.ControlFlowGraph, this.MainMethodSymbol, semanticModel); this.ExplodedGraph = new CSharpExplodedGraph(this.ControlFlowGraph, this.MainMethodSymbol, semanticModel, this.LiveVariableAnalysis); this.ExplodedGraph.InstructionProcessed += (sender, args) => { this.NumberOfProcessedInstructions++; }; this.ExplodedGraph.ExplorationEnded += (sender, args) => { this.ExplorationEnded = true; }; this.ExplodedGraph.MaxStepCountReached += (sender, args) => { this.MaxStepCountReached = true; }; this.ExplodedGraph.ExitBlockReached += (sender, args) => { this.NumberOfExitBlockReached++; }; }
private static void CheckForDeadStores(CSharpSyntaxNode node, ISymbol declaration, SyntaxNodeAnalysisContext context) { if (declaration == null || !CSharpControlFlowGraph.TryGet(node, context.SemanticModel, out var cfg)) { return; } var lva = CSharpLiveVariableAnalysis.Analyze(cfg, declaration, context.SemanticModel); foreach (var block in cfg.Blocks) { CheckCfgBlockForDeadStores(block, lva.GetLiveOut(block), lva.CapturedVariables, node, declaration, context); } }
private static UCFG CreateUcfgForConstructor(string code, string name) { var(syntaxTree, semanticModel) = TestHelper.Compile(code, Verifier.SystemWebMvcAssembly); var ctor = syntaxTree.GetRoot() .DescendantNodes() .OfType <ConstructorDeclarationSyntax>() .First(m => m.Identifier.ValueText == name); var builder = new UniversalControlFlowGraphBuilder(); var ucfg = builder.Build(semanticModel, ctor, semanticModel.GetDeclaredSymbol(ctor), CSharpControlFlowGraph.Create(ctor.Body, semanticModel)); return(ucfg); }
private static void CheckForNoExitProperty(SyntaxNodeAnalysisContext c) { var property = (PropertyDeclarationSyntax)c.Node; var propertySymbol = c.SemanticModel.GetDeclaredSymbol(property); if (propertySymbol == null) { return; } IControlFlowGraph cfg; if (property.ExpressionBody?.Expression != null) { if (CSharpControlFlowGraph.TryGet(property.ExpressionBody.Expression, c.SemanticModel, out cfg)) { var walker = new CfgWalkerForProperty( new RecursionAnalysisContext(cfg, propertySymbol, property.Identifier.GetLocation(), c), "property's recursion", isSetAccessor: false); walker.CheckPaths(); } return; } var accessors = property.AccessorList?.Accessors.Where(a => a.HasBodyOrExpressionBody()); if (accessors != null) { foreach (var accessor in accessors) { var bodyNode = (CSharpSyntaxNode)accessor.Body ?? accessor.ExpressionBody(); if (CSharpControlFlowGraph.TryGet(bodyNode, c.SemanticModel, out cfg)) { var walker = new CfgWalkerForProperty( new RecursionAnalysisContext(cfg, propertySymbol, accessor.Keyword.GetLocation(), c), "property accessor's recursion", isSetAccessor: accessor.Keyword.IsKind(SyntaxKind.SetKeyword)); walker.CheckPaths(); CheckInfiniteJumpLoop(bodyNode, cfg, "property accessor", c); } } } }
private static bool IsSymbolFirstSetInCtor(ISymbol declaredSymbol, CtorDeclarationTuple ctor) { if (ctor.SyntaxNode.Initializer != null && ctor.SyntaxNode.Initializer.ThisOrBaseKeyword.IsKind(SyntaxKind.ThisKeyword)) { // Calls another ctor, which is also checked. return(true); } if (!CSharpControlFlowGraph.TryGet(ctor.SyntaxNode.Body, ctor.SemanticModel, out var cfg)) { return(false); } var checker = new MemberInitializerRedundancyChecker(cfg, declaredSymbol, ctor.SemanticModel); return(checker.CheckAllPaths()); }
private static void CheckForRedundantJumps(CSharpSyntaxNode node, SyntaxNodeAnalysisContext context) { if (!CSharpControlFlowGraph.TryGet(node, context.SemanticModel, out var cfg)) { return; } var yieldStatementCount = node.DescendantNodes().OfType <YieldStatementSyntax>().Count(); var removableJumps = cfg.Blocks .OfType <JumpBlock>() .Where(jumpBlock => IsJumpRemovable(jumpBlock, yieldStatementCount)); foreach (var jumpBlock in removableJumps) { context.ReportDiagnosticWhenActive(Diagnostic.Create(rule, jumpBlock.JumpNode.GetLocation())); } }
private void WriteUcfg <TDeclarationSyntax>(SyntaxNodeAnalysisContext context, Func <TDeclarationSyntax, CSharpSyntaxNode> getBody) where TDeclarationSyntax : SyntaxNode { var declaration = (TDeclarationSyntax)context.Node; var symbol = context.SemanticModel.GetDeclaredSymbol(declaration); var methodSymbol = (symbol is IPropertySymbol propertySymbol) ? propertySymbol.GetMethod // We are in PropertyDeclarationSyntax : symbol as IMethodSymbol; // all other are methods if (methodSymbol == null || methodSymbol.IsAbstract || methodSymbol.IsExtern || !CSharpControlFlowGraph.TryGet(getBody(declaration), context.SemanticModel, out var cfg)) { return; } try { var ucfg = new UcfgFactory(context.SemanticModel) .Create(declaration, methodSymbol, cfg); if (!IsValid(ucfg)) { return; } var fileName = $"{this.projectBuildId}_{Interlocked.Increment(ref this.protobufFileIndex)}"; WriteProtobuf(ucfg, Path.Combine(this.protobufDirectory, $"ucfg_{fileName}.pb")); if (ShouldGenerateDot) { WriteDot(Path.Combine(this.protobufDirectory, $"ucfg_{fileName}.dot"), writer => UcfgSerializer.Serialize(ucfg, writer)); WriteDot(Path.Combine(this.protobufDirectory, $"cfg_{fileName}.dot"), writer => CfgSerializer.Serialize(ucfg.MethodId, cfg, writer)); } } catch (UcfgException) when(!DebugHelper.IsInternalDebuggingContext()) { // Ignore the exception in production } }
public void ExplodedGraph_AllBranchesVisited() { string testInput = "int i = 1; switch (i) { case 1: default: cw1(); break; case 2: cw2(); break; }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfCw1InstructionVisits = 0; var numberOfCw2InstructionVisits = 0; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "cw1()") { numberOfCw1InstructionVisits++; } if (args.Instruction.ToString() == "cw2()") { numberOfCw2InstructionVisits++; } }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); numberOfExitBlockReached.Should().Be(1); numberOfCw1InstructionVisits.Should().Be(1); numberOfCw2InstructionVisits.Should().Be(1); }
private static void Analyze(CSharpSyntaxNode declarationBody, ISymbol symbol, Action <CSharpExplodedGraph, SyntaxNodeAnalysisContext> analyze, SyntaxNodeAnalysisContext context) { if (declarationBody == null || declarationBody.ContainsDiagnostics) { return; } if (!CSharpControlFlowGraph.TryGet(declarationBody, context.SemanticModel, out var cfg)) { return; } var lva = CSharpLiveVariableAnalysis.Analyze(cfg, symbol, context.SemanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, symbol, context.SemanticModel, lva); analyze(explodedGraph, context); }
private static void CheckForNoExitMethod(SyntaxNodeAnalysisContext c) { var method = (MethodDeclarationSyntax)c.Node; var methodSymbol = c.SemanticModel.GetDeclaredSymbol(method); if (methodSymbol == null) { return; } if (CSharpControlFlowGraph.TryGet(method.Body, c.SemanticModel, out var cfg) || CSharpControlFlowGraph.TryGet(method.ExpressionBody?.Expression, c.SemanticModel, out cfg)) { var walker = new CfgWalkerForMethod( new RecursionAnalysisContext(cfg, methodSymbol, method.Identifier.GetLocation(), c)); walker.CheckPaths(); CheckInfiniteJumpLoop(method.Body, cfg, "method", c); } }
public LiveVariableAnalysisContext(string methodBody, string localFunctionName = null) { var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, methodBody), "Main", out var semanticModel); IMethodSymbol symbol; CSharpSyntaxNode body; if (localFunctionName == null) { symbol = semanticModel.GetDeclaredSymbol(method); body = method.Body; } else { var function = (LocalFunctionStatementSyntaxWrapper)method.DescendantNodes().Single(x => x.Kind() == SyntaxKindEx.LocalFunctionStatement && ((LocalFunctionStatementSyntaxWrapper)x).Identifier.Text == localFunctionName); symbol = semanticModel.GetDeclaredSymbol(function) as IMethodSymbol; body = (CSharpSyntaxNode)function.Body ?? function.ExpressionBody; } this.CFG = CSharpControlFlowGraph.Create(body, semanticModel); this.LVA = CSharpLiveVariableAnalysis.Analyze(this.CFG, symbol, semanticModel); }
public void ExplodedGraph_BothBranchesVisited_StateMerge() { var testInput = "var a = !true; bool b; if (inParameter) { b = false; } else { b = false; } a = b;"; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out var semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfLastInstructionVisits = 0; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = b") { args.ProgramState.GetSymbolValue(aSymbol).Should().Be(SymbolicValue.False); numberOfLastInstructionVisits++; } }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); numberOfExitBlockReached.Should().Be(1); numberOfLastInstructionVisits.Should().Be(1); }
public void ExplodedGraph_SingleBranchVisited_And() { var testInput = "var a = false; if (a && !a) { a = true; }"; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out var semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var varDeclarators = method.DescendantNodes().OfType <VariableDeclaratorSyntax>(); var aSymbol = semanticModel.GetDeclaredSymbol(varDeclarators.First(d => d.Identifier.ToString() == "a")); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "a = !true") { args.ProgramState.GetSymbolValue(aSymbol).Should().Be(SymbolicValue.False); // Roslyn is clever !true has const value. } if (args.Instruction.ToString() == "!a") { Execute.Assertion.FailWith("We should never get into this branch"); } }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); numberOfExitBlockReached.Should().Be(1); }
private static void CheckForDeadStores(CSharpSyntaxNode node, ISymbol declaration, SyntaxNodeAnalysisContext context) { if (declaration == null || node == null || // Currently the tuple expressions are not supported and this is known to cause false positives. // Please check: // - community feedback: https://github.com/SonarSource/sonar-dotnet/issues/3094 // - implementation ticket: https://github.com/SonarSource/sonar-dotnet/issues/2933 node.DescendantNodes().AnyOfKind(SyntaxKindEx.TupleExpression) || !CSharpControlFlowGraph.TryGet(node, context.SemanticModel, out var cfg)) { return; } var lva = CSharpLiveVariableAnalysis.Analyze(cfg, declaration, context.SemanticModel); foreach (var block in cfg.Blocks) { CheckCfgBlockForDeadStores(block, lva.GetLiveOut(block), lva.CapturedVariables, node, declaration, context); } }
public void ExplodedGraph_NonLocalNorFieldSymbolBranching() { string testInput = "if (Property) { cw(); }"; SemanticModel semanticModel; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var propertySymbol = semanticModel.GetSymbolInfo( method.DescendantNodes().OfType <IdentifierNameSyntax>().First(d => d.Identifier.ToString() == "Property")).Symbol; propertySymbol.Should().NotBeNull(); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "Property") { args.ProgramState.GetSymbolValue(propertySymbol).Should().BeNull(); } }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); numberOfExitBlockReached.Should().Be(1); }
public void ExplodedGraph_SequentialInput_OutParameter() { var testInput = "outParameter = true;"; var method = ControlFlowGraphTest.CompileWithMethodBody(string.Format(TestInput, testInput), "Bar", out var semanticModel); var methodSymbol = semanticModel.GetDeclaredSymbol(method); var parameters = method.DescendantNodes().OfType <ParameterSyntax>(); var outParameterSymbol = semanticModel.GetDeclaredSymbol(parameters.First(d => d.Identifier.ToString() == "outParameter")); var cfg = CSharpControlFlowGraph.Create(method.Body, semanticModel); var lva = CSharpLiveVariableAnalysis.Analyze(cfg, methodSymbol, semanticModel); var explodedGraph = new CSharpExplodedGraph(cfg, methodSymbol, semanticModel, lva); var explorationEnded = false; explodedGraph.ExplorationEnded += (sender, args) => { explorationEnded = true; }; var numberOfExitBlockReached = 0; explodedGraph.ExitBlockReached += (sender, args) => { numberOfExitBlockReached++; }; var numberOfProcessedInstructions = 0; explodedGraph.InstructionProcessed += (sender, args) => { numberOfProcessedInstructions++; if (args.Instruction.ToString() == "outParameter = true") { args.ProgramState.GetSymbolValue(outParameterSymbol) .Should().Be(SymbolicValue.True); } }; explodedGraph.Walk(); explorationEnded.Should().BeTrue(); numberOfProcessedInstructions.Should().Be(2); numberOfExitBlockReached.Should().Be(1); }