private void Build() { // Set up the current method locals DeclareLocals(_currentScope, _topLevelMethod.Parameters); // Treat 'this' as a formal parameter of the top-level method if (_topLevelMethod.TryGetThisParameter(out var thisParam) && (object)thisParam != null) { DeclareLocals(_currentScope, ImmutableArray.Create <Symbol>(thisParam)); } Visit(_currentScope.BoundNode); // Clean Up Resources foreach (var scopes in _scopesAfterLabel.Values) { scopes.Free(); } _scopesAfterLabel.Free(); Debug.Assert(_labelsInScope.Count == 1); var labels = _labelsInScope.Pop(); labels.Free(); _labelsInScope.Free(); }
protected override void Free() { _labelsDefined.Free(); _labelsUsed.Free(); _usingDeclarations.Free(); base.Free(); }
public void Free() { if (_lazyMap != null) { _lazyMap.Free(); _lazyMap = null; } }
public void Free() { foreach (var item in ThrowLocations) { item.Value.Free(); } ThrowLocations.Free(); CatchBlockUsed.Free(); }
public static ImmutableDictionary <K, ImmutableArray <V> > ToImmutableMultiDictionaryAndFree <K, V>(this PooledDictionary <K, ArrayBuilder <V> > builders) { var result = ImmutableDictionary.CreateBuilder <K, ImmutableArray <V> >(); foreach (var(key, items) in builders) { result.Add(key, items.ToImmutableAndFree()); } builders.Free(); return(result.ToImmutable()); }
internal ImmutableArray <GeneratedSourceText> ToImmutableAndFree() { // https://github.com/dotnet/roslyn/issues/42627: This needs to be consistently ordered ArrayBuilder <GeneratedSourceText> builder = ArrayBuilder <GeneratedSourceText> .GetInstance(); foreach (var(hintName, sourceText) in _sourcesAdded) { builder.Add(new GeneratedSourceText(hintName, sourceText)); } _sourcesAdded.Free(); return(builder.ToImmutableAndFree()); }
public static Dictionary <K, V> ToDictionaryAndFree <K, V>(this PooledDictionary <K, V> builders) { var dictionary = new Dictionary <K, V>(builders.Count); foreach (var(key, items) in builders) { dictionary.Add(key, items); } builders.Free(); return(dictionary); }
public static Dictionary <K, ImmutableArray <V> > ToMultiDictionaryAndFree <K, V>(this PooledDictionary <K, ArrayBuilder <V> > builders) { var dictionary = new Dictionary <K, ImmutableArray <V> >(builders.Count); foreach (var(key, items) in builders) { dictionary.Add(key, items.ToImmutableAndFree()); } builders.Free(); return(dictionary); }
/// <summary> /// Produce a topological sort of a given directed acyclic graph, given a set of nodes which include all nodes /// that have no predecessors. Any nodes not in the given set, but reachable through successors, will be added /// to the result. This is an iterative rather than recursive implementation, so it is unlikely to cause a stack /// overflow. /// </summary> /// <typeparam name="TNode">The type of the node</typeparam> /// <param name="nodes">Any subset of the nodes that includes all nodes with no predecessors</param> /// <param name="successors">A function mapping a node to its set of successors</param> /// <param name="result">A list of all reachable nodes, in which each node always precedes its successors</param> /// <returns>true if successful; false if not successful due to cycles in the graph</returns> public static bool TryIterativeSort <TNode>( IEnumerable <TNode> nodes, Func <TNode, ImmutableArray <TNode> > successors, out ImmutableArray <TNode> result ) where TNode : notnull { // First, count the predecessors of each node PooledDictionary <TNode, int> predecessorCounts = PredecessorCounts( nodes, successors, out ImmutableArray <TNode> allNodes ); // Initialize the ready set with those nodes that have no predecessors var ready = ArrayBuilder <TNode> .GetInstance(); foreach (TNode node in allNodes) { if (predecessorCounts[node] == 0) { ready.Push(node); } } // Process the ready set. Output a node, and decrement the predecessor count of its successors. var resultBuilder = ArrayBuilder <TNode> .GetInstance(); while (ready.Count != 0) { var node = ready.Pop(); resultBuilder.Add(node); foreach (var succ in successors(node)) { var count = predecessorCounts[succ]; Debug.Assert(count != 0); predecessorCounts[succ] = count - 1; if (count == 1) { ready.Push(succ); } } } // At this point all the nodes should have been output, otherwise there was a cycle bool hadCycle = predecessorCounts.Count != resultBuilder.Count; result = hadCycle ? ImmutableArray <TNode> .Empty : resultBuilder.ToImmutable(); predecessorCounts.Free(); ready.Free(); resultBuilder.Free(); return(!hadCycle); }
protected override void Dispose(bool disposing) { if (IsDisposed) { return; } if (disposing) { _coreAnalysisData.Free(); _coreAnalysisData = null !; } base.Dispose(disposing); }
public static ImmutableArray <TNode> IterativeSort <TNode>(IEnumerable <TNode> nodes, Func <TNode, ImmutableArray <TNode> > successors) { // First, count the predecessors of each node PooledDictionary <TNode, int> predecessorCounts = PredecessorCounts(nodes, successors, out ImmutableArray <TNode> allNodes); // Initialize the ready set with those nodes that have no predecessors var ready = ArrayBuilder <TNode> .GetInstance(); foreach (TNode node in allNodes) { if (predecessorCounts[node] == 0) { ready.Push(node); } } // Process the ready set. Output a node, and decrement the predecessor count of its successors. var resultBuilder = ImmutableArray.CreateBuilder <TNode>(); while (ready.Count != 0) { var node = ready.Pop(); resultBuilder.Add(node); foreach (var succ in successors(node)) { var count = predecessorCounts[succ]; Debug.Assert(count != 0); predecessorCounts[succ] = count - 1; if (count == 1) { ready.Push(succ); } } } // At this point all the nodes should have been output, otherwise there was a cycle if (predecessorCounts.Count != resultBuilder.Count) { throw new ArgumentException("Cycle in the input graph"); } predecessorCounts.Free(); ready.Free(); return(resultBuilder.ToImmutable()); }
private void GenerateImpl() { SetInitialDebugDocument(); // Synthesized methods should have a sequence point // at offset 0 to ensure correct stepping behavior. if (_emitPdbSequencePoints && _method.IsImplicitlyDeclared) { _builder.DefineInitialHiddenSequencePoint(); } try { EmitStatement(_boundBody); if (_indirectReturnState == IndirectReturnState.Needed) { // it is unfortunate that return was not handled while we were in scope of the method // it can happen in rare cases involving exception handling (for example all returns were from a try) // in such case we can still handle return here. HandleReturn(); } if (!_diagnostics.HasAnyErrors()) { _builder.Realize(); } } catch (EmitCancelledException) { Debug.Assert(_diagnostics.HasAnyErrors()); } _synthesizedLocalOrdinals.Free(); Debug.Assert(!(_expressionTemps?.Count > 0), "leaking expression temps?"); _expressionTemps?.Free(); _savedSequencePoints?.Free(); }
protected override void Free() { _variableSlot.Free(); base.Free(); }
private void ResolveAndBindMissingAssemblies( TCompilation compilation, ImmutableArray <AssemblyData> explicitAssemblies, ImmutableArray <PEModule> explicitModules, ImmutableArray <MetadataReference> explicitReferences, ImmutableArray <ResolvedReference> explicitReferenceMap, MetadataReferenceResolver resolver, MetadataImportOptions importOptions, bool supersedeLowerVersions, [In, Out] ArrayBuilder <AssemblyReferenceBinding[]> referenceBindings, [In, Out] Dictionary <string, List <ReferencedAssemblyIdentity> > assemblyReferencesBySimpleName, out ImmutableArray <AssemblyData> allAssemblies, out ImmutableArray <MetadataReference> metadataReferences, out ImmutableArray <ResolvedReference> resolvedReferences, DiagnosticBag resolutionDiagnostics) { Debug.Assert(explicitAssemblies[0] is AssemblyDataForAssemblyBeingBuilt); Debug.Assert(referenceBindings.Count == explicitAssemblies.Length); Debug.Assert(explicitReferences.Length == explicitReferenceMap.Length); // -1 for assembly being built: int totalReferencedAssemblyCount = explicitAssemblies.Length - 1; var implicitAssemblies = ArrayBuilder <AssemblyData> .GetInstance(); // tracks identities we already asked the resolver to resolve: var requestedIdentities = PooledHashSet <AssemblyIdentity> .GetInstance(); PooledDictionary <AssemblyIdentity, PortableExecutableReference> previouslyResolvedAssembliesOpt = null; // Avoid resolving previously resolved missing references. If we call to the resolver again we would create new assembly symbols for them, // which would not match the previously created ones. As a result we would get duplicate PE types and conversion errors. var previousScriptCompilation = compilation.ScriptCompilationInfo?.PreviousScriptCompilation; if (previousScriptCompilation != null) { previouslyResolvedAssembliesOpt = PooledDictionary <AssemblyIdentity, PortableExecutableReference> .GetInstance(); foreach (var entry in previousScriptCompilation.GetBoundReferenceManager().GetImplicitlyResolvedAssemblyReferences()) { previouslyResolvedAssembliesOpt.Add(entry.Key, entry.Value); } } var metadataReferencesBuilder = ArrayBuilder <MetadataReference> .GetInstance(); Dictionary <MetadataReference, MergedAliases> lazyAliasMap = null; // metadata references and corresponding bindings of their references, used to calculate a fixed point: var referenceBindingsToProcess = ArrayBuilder <(MetadataReference, ArraySegment <AssemblyReferenceBinding>)> .GetInstance(); // collect all missing identities, resolve the assemblies and bind their references against explicit definitions: GetInitialReferenceBindingsToProcess(explicitModules, explicitReferences, explicitReferenceMap, referenceBindings, totalReferencedAssemblyCount, referenceBindingsToProcess); // NB: includes the assembly being built: int explicitAssemblyCount = explicitAssemblies.Length; try { while (referenceBindingsToProcess.Count > 0) { var referenceAndBindings = referenceBindingsToProcess.Pop(); var requestingReference = referenceAndBindings.Item1; var bindings = referenceAndBindings.Item2; foreach (var binding in bindings) { // only attempt to resolve unbound references (regardless of version difference of the bound ones) if (binding.IsBound) { continue; } if (!requestedIdentities.Add(binding.ReferenceIdentity)) { continue; } PortableExecutableReference resolvedReference; if (previouslyResolvedAssembliesOpt == null || !previouslyResolvedAssembliesOpt.TryGetValue(binding.ReferenceIdentity, out resolvedReference)) { resolvedReference = resolver.ResolveMissingAssembly(requestingReference, binding.ReferenceIdentity); if (resolvedReference == null) { continue; } } var data = ResolveMissingAssembly(binding.ReferenceIdentity, resolvedReference, importOptions, resolutionDiagnostics); if (data == null) { continue; } // The resolver may return different version than we asked for, so it may happen that // it returns the same identity for two different input identities (e.g. if a higher version // of an assembly is available than what the assemblies reference: "A, v1" -> "A, v3" and "A, v2" -> "A, v3"). // If such case occurs merge the properties (aliases) of the resulting references in the same way we do // during initial explicit references resolution. // -1 for assembly being built: int index = explicitAssemblyCount - 1 + metadataReferencesBuilder.Count; var existingReference = TryAddAssembly(data.Identity, resolvedReference, index, resolutionDiagnostics, Location.None, assemblyReferencesBySimpleName, supersedeLowerVersions); if (existingReference != null) { MergeReferenceProperties(existingReference, resolvedReference, resolutionDiagnostics, ref lazyAliasMap); continue; } metadataReferencesBuilder.Add(resolvedReference); implicitAssemblies.Add(data); var referenceBinding = data.BindAssemblyReferences(explicitAssemblies, IdentityComparer); referenceBindings.Add(referenceBinding); referenceBindingsToProcess.Push((resolvedReference, new ArraySegment <AssemblyReferenceBinding>(referenceBinding))); } } if (implicitAssemblies.Count == 0) { Debug.Assert(lazyAliasMap == null); resolvedReferences = ImmutableArray <ResolvedReference> .Empty; metadataReferences = ImmutableArray <MetadataReference> .Empty; allAssemblies = explicitAssemblies; return; } // Rebind assembly references that were initially missing. All bindings established above // are against explicitly specified references. allAssemblies = explicitAssemblies.AddRange(implicitAssemblies); for (int bindingsIndex = 0; bindingsIndex < referenceBindings.Count; bindingsIndex++) { var referenceBinding = referenceBindings[bindingsIndex]; for (int i = 0; i < referenceBinding.Length; i++) { var binding = referenceBinding[i]; // We don't rebind references bound to a non-matching version of a reference that was explicitly // specified, even if we have a better version now. if (binding.IsBound) { continue; } // We only need to resolve against implicitly resolved assemblies, // since we already resolved against explicitly specified ones. referenceBinding[i] = ResolveReferencedAssembly( binding.ReferenceIdentity, allAssemblies, explicitAssemblyCount, IdentityComparer); } } UpdateBindingsOfAssemblyBeingBuilt(referenceBindings, explicitAssemblyCount, implicitAssemblies); metadataReferences = metadataReferencesBuilder.ToImmutable(); resolvedReferences = ToResolvedAssemblyReferences(metadataReferences, lazyAliasMap, explicitAssemblyCount); } finally { implicitAssemblies.Free(); requestedIdentities.Free(); referenceBindingsToProcess.Free(); metadataReferencesBuilder.Free(); previouslyResolvedAssembliesOpt?.Free(); } }
private TaintedDataConfig(Compilation compilation) { this.WellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation); this.SourceSymbolMap = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SourceInfo> > >(); this.SanitizerSymbolMap = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SanitizerInfo> > >(); this.SinkSymbolMap = new Dictionary <SinkKind, Lazy <TaintedDataSymbolMap <SinkInfo> > >(); // For tainted data rules with the same set of sources, we'll reuse the same TaintedDataSymbolMap<SourceInfo> instance. // Same for sanitizers. PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > sourcesToSymbolMap = PooledDictionary <ImmutableHashSet <SourceInfo>, Lazy <TaintedDataSymbolMap <SourceInfo> > > .GetInstance(); PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > sanitizersToSymbolMap = PooledDictionary <ImmutableHashSet <SanitizerInfo>, Lazy <TaintedDataSymbolMap <SanitizerInfo> > > .GetInstance(); // Build a mapping of (sourceSet, sanitizerSet) -> (sinkKinds, sinkSet), so we'll reuse the same TaintedDataSymbolMap<SinkInfo> instance. PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> sourceSanitizersToSinks = PooledDictionary <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> .GetInstance(); try { // Using LazyThreadSafetyMode.ExecutionAndPublication to avoid instantiating multiple times. foreach (SinkKind sinkKind in Enum.GetValues(typeof(SinkKind))) { ImmutableHashSet <SourceInfo> sources = GetSourceInfos(sinkKind); if (!sourcesToSymbolMap.TryGetValue(sources, out Lazy <TaintedDataSymbolMap <SourceInfo> > lazySourceSymbolMap)) { lazySourceSymbolMap = new Lazy <TaintedDataSymbolMap <SourceInfo> >( () => { return(new TaintedDataSymbolMap <SourceInfo>(this.WellKnownTypeProvider, sources)); }, LazyThreadSafetyMode.ExecutionAndPublication); sourcesToSymbolMap.Add(sources, lazySourceSymbolMap); } this.SourceSymbolMap.Add(sinkKind, lazySourceSymbolMap); ImmutableHashSet <SanitizerInfo> sanitizers = GetSanitizerInfos(sinkKind); if (!sanitizersToSymbolMap.TryGetValue(sanitizers, out Lazy <TaintedDataSymbolMap <SanitizerInfo> > lazySanitizerSymbolMap)) { lazySanitizerSymbolMap = new Lazy <TaintedDataSymbolMap <SanitizerInfo> >( () => { return(new TaintedDataSymbolMap <SanitizerInfo>(this.WellKnownTypeProvider, sanitizers)); }, LazyThreadSafetyMode.ExecutionAndPublication); sanitizersToSymbolMap.Add(sanitizers, lazySanitizerSymbolMap); } this.SanitizerSymbolMap.Add(sinkKind, lazySanitizerSymbolMap); ImmutableHashSet <SinkInfo> sinks = GetSinkInfos(sinkKind); if (!sourceSanitizersToSinks.TryGetValue((sources, sanitizers), out (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)sinksPair)) { sinksPair = (ImmutableHashSet.CreateBuilder <SinkKind>(), ImmutableHashSet.CreateBuilder <SinkInfo>()); sourceSanitizersToSinks.Add((sources, sanitizers), sinksPair); } sinksPair.SinkKinds.Add(sinkKind); sinksPair.SinkInfos.UnionWith(sinks); } foreach (KeyValuePair <(ImmutableHashSet <SourceInfo> SourceInfos, ImmutableHashSet <SanitizerInfo> SanitizerInfos), (ImmutableHashSet <SinkKind> .Builder SinkKinds, ImmutableHashSet <SinkInfo> .Builder SinkInfos)> kvp in sourceSanitizersToSinks) { ImmutableHashSet <SinkInfo> sinks = kvp.Value.SinkInfos.ToImmutable(); Lazy <TaintedDataSymbolMap <SinkInfo> > lazySinkSymbolMap = new Lazy <TaintedDataSymbolMap <SinkInfo> >( () => { return(new TaintedDataSymbolMap <SinkInfo>(this.WellKnownTypeProvider, sinks)); }, LazyThreadSafetyMode.ExecutionAndPublication); foreach (SinkKind sinkKind in kvp.Value.SinkKinds) { this.SinkSymbolMap.Add(sinkKind, lazySinkSymbolMap); } } } finally { sourcesToSymbolMap.Free(); sanitizersToSymbolMap.Free(); sourceSanitizersToSinks.Free(); } }
private static void GetFlowGraph(System.Text.StringBuilder stringBuilder, Compilation compilation, ControlFlowGraph graph, ControlFlowRegion enclosing, string idSuffix, int indent) { ImmutableArray <BasicBlock> blocks = graph.Blocks; var visitor = TestOperationVisitor.Singleton; ControlFlowRegion currentRegion = graph.Root; bool lastPrintedBlockIsInCurrentRegion = true; PooledDictionary <ControlFlowRegion, int> regionMap = buildRegionMap(); var localFunctionsMap = PooledDictionary <IMethodSymbol, ControlFlowGraph> .GetInstance(); var anonymousFunctionsMap = PooledDictionary <IFlowAnonymousFunctionOperation, ControlFlowGraph> .GetInstance(); for (int i = 0; i < blocks.Length; i++) { var block = blocks[i]; Assert.Equal(i, block.Ordinal); switch (block.Kind) { case BasicBlockKind.Block: Assert.NotEqual(0, i); Assert.NotEqual(blocks.Length - 1, i); break; case BasicBlockKind.Entry: Assert.Equal(0, i); Assert.Empty(block.Operations); Assert.Empty(block.Predecessors); Assert.Null(block.BranchValue); Assert.NotNull(block.FallThroughSuccessor); Assert.NotNull(block.FallThroughSuccessor.Destination); Assert.Null(block.ConditionalSuccessor); Assert.Same(graph.Root, currentRegion); Assert.Same(currentRegion, block.EnclosingRegion); Assert.Equal(0, currentRegion.FirstBlockOrdinal); Assert.Same(enclosing, currentRegion.EnclosingRegion); Assert.Null(currentRegion.ExceptionType); Assert.Empty(currentRegion.Locals); Assert.Empty(currentRegion.LocalFunctions); Assert.Equal(ControlFlowRegionKind.Root, currentRegion.Kind); Assert.True(block.IsReachable); break; case BasicBlockKind.Exit: Assert.Equal(blocks.Length - 1, i); Assert.Empty(block.Operations); Assert.Null(block.FallThroughSuccessor); Assert.Null(block.ConditionalSuccessor); Assert.Null(block.BranchValue); Assert.Same(graph.Root, currentRegion); Assert.Same(currentRegion, block.EnclosingRegion); Assert.Equal(i, currentRegion.LastBlockOrdinal); break; default: Assert.False(true, $"Unexpected block kind {block.Kind}"); break; } if (block.EnclosingRegion != currentRegion) { enterRegions(block.EnclosingRegion, block.Ordinal); } if (!lastPrintedBlockIsInCurrentRegion) { stringBuilder.AppendLine(); } appendLine($"Block[{getBlockId(block)}] - {block.Kind}{(block.IsReachable ? "" : " [UnReachable]")}"); var predecessors = block.Predecessors; if (!predecessors.IsEmpty) { appendIndent(); stringBuilder.Append(" Predecessors:"); int previousPredecessorOrdinal = -1; for (var predecessorIndex = 0; predecessorIndex < predecessors.Length; predecessorIndex++) { var predecessorBranch = predecessors[predecessorIndex]; Assert.Same(block, predecessorBranch.Destination); var predecessor = predecessorBranch.Source; Assert.True(previousPredecessorOrdinal < predecessor.Ordinal); previousPredecessorOrdinal = predecessor.Ordinal; Assert.Same(blocks[predecessor.Ordinal], predecessor); if (predecessorBranch.IsConditionalSuccessor) { Assert.Same(predecessor.ConditionalSuccessor, predecessorBranch); Assert.NotEqual(ControlFlowConditionKind.None, predecessor.ConditionKind); } else { Assert.Same(predecessor.FallThroughSuccessor, predecessorBranch); } stringBuilder.Append($" [{getBlockId(predecessor)}"); if (predecessorIndex < predecessors.Length - 1 && predecessors[predecessorIndex + 1].Source == predecessor) { // Multiple branches from same predecessor - one must be conditional and other fall through. Assert.True(predecessorBranch.IsConditionalSuccessor); predecessorIndex++; predecessorBranch = predecessors[predecessorIndex]; Assert.Same(predecessor.FallThroughSuccessor, predecessorBranch); Assert.False(predecessorBranch.IsConditionalSuccessor); stringBuilder.Append("*2"); } stringBuilder.Append("]"); } stringBuilder.AppendLine(); } else if (block.Kind != BasicBlockKind.Entry) { appendLine(" Predecessors (0)"); } var statements = block.Operations; appendLine($" Statements ({statements.Length})"); foreach (var statement in statements) { validateRoot(statement); stringBuilder.AppendLine(getOperationTree(statement)); } ControlFlowBranch conditionalBranch = block.ConditionalSuccessor; if (block.ConditionKind != ControlFlowConditionKind.None) { Assert.NotNull(conditionalBranch); Assert.True(conditionalBranch.IsConditionalSuccessor); Assert.Same(block, conditionalBranch.Source); if (conditionalBranch.Destination != null) { Assert.Same(blocks[conditionalBranch.Destination.Ordinal], conditionalBranch.Destination); } Assert.NotEqual(ControlFlowBranchSemantics.Return, conditionalBranch.Semantics); Assert.NotEqual(ControlFlowBranchSemantics.Throw, conditionalBranch.Semantics); Assert.NotEqual(ControlFlowBranchSemantics.StructuredExceptionHandling, conditionalBranch.Semantics); Assert.True(block.ConditionKind == ControlFlowConditionKind.WhenTrue || block.ConditionKind == ControlFlowConditionKind.WhenFalse); string jumpIfTrue = block.ConditionKind == ControlFlowConditionKind.WhenTrue ? "True" : "False"; appendLine($" Jump if {jumpIfTrue} ({conditionalBranch.Semantics}) to Block[{getDestinationString(ref conditionalBranch)}]"); IOperation value = block.BranchValue; Assert.NotNull(value); validateRoot(value); stringBuilder.Append(getOperationTree(value)); validateBranch(block, conditionalBranch); stringBuilder.AppendLine(); } else { Assert.Null(conditionalBranch); Assert.Equal(ControlFlowConditionKind.None, block.ConditionKind); } ControlFlowBranch nextBranch = block.FallThroughSuccessor; if (block.Kind == BasicBlockKind.Exit) { Assert.Null(nextBranch); Assert.Null(block.BranchValue); } else { Assert.NotNull(nextBranch); Assert.False(nextBranch.IsConditionalSuccessor); Assert.Same(block, nextBranch.Source); if (nextBranch.Destination != null) { Assert.Same(blocks[nextBranch.Destination.Ordinal], nextBranch.Destination); } if (nextBranch.Semantics == ControlFlowBranchSemantics.StructuredExceptionHandling) { Assert.Null(nextBranch.Destination); Assert.Equal(block.EnclosingRegion.LastBlockOrdinal, block.Ordinal); Assert.True(block.EnclosingRegion.Kind == ControlFlowRegionKind.Filter || block.EnclosingRegion.Kind == ControlFlowRegionKind.Finally); } appendLine($" Next ({nextBranch.Semantics}) Block[{getDestinationString(ref nextBranch)}]"); IOperation value = block.ConditionKind == ControlFlowConditionKind.None ? block.BranchValue : null; if (value != null) { Assert.True(ControlFlowBranchSemantics.Return == nextBranch.Semantics || ControlFlowBranchSemantics.Throw == nextBranch.Semantics); validateRoot(value); stringBuilder.Append(getOperationTree(value)); } else { Assert.NotEqual(ControlFlowBranchSemantics.Return, nextBranch.Semantics); Assert.NotEqual(ControlFlowBranchSemantics.Throw, nextBranch.Semantics); } validateBranch(block, nextBranch); } validateLocalsAndMethodsLifetime(block); if (currentRegion.LastBlockOrdinal == block.Ordinal && i != blocks.Length - 1) { leaveRegions(block.EnclosingRegion, block.Ordinal); } else { lastPrintedBlockIsInCurrentRegion = true; } } foreach (IMethodSymbol m in graph.LocalFunctions) { ControlFlowGraph g = localFunctionsMap[m]; Assert.Same(g, graph.GetLocalFunctionControlFlowGraph(m)); } Assert.Equal(graph.LocalFunctions.Length, localFunctionsMap.Count); foreach (KeyValuePair <IFlowAnonymousFunctionOperation, ControlFlowGraph> pair in anonymousFunctionsMap) { Assert.Same(pair.Value, graph.GetAnonymousFunctionControlFlowGraph(pair.Key)); } regionMap.Free(); localFunctionsMap.Free(); anonymousFunctionsMap.Free(); return; string getDestinationString(ref ControlFlowBranch branch) { return(branch.Destination != null?getBlockId(branch.Destination) : "null"); } PooledObjects.PooledDictionary <ControlFlowRegion, int> buildRegionMap() { var result = PooledObjects.PooledDictionary <ControlFlowRegion, int> .GetInstance(); int ordinal = 0; visit(graph.Root); void visit(ControlFlowRegion region) { result.Add(region, ordinal++); foreach (ControlFlowRegion r in region.NestedRegions) { visit(r); } } return(result); } void appendLine(string line) { appendIndent(); stringBuilder.AppendLine(line); } void appendIndent() { stringBuilder.Append(' ', indent); } void printLocals(ControlFlowRegion region) { if (!region.Locals.IsEmpty) { appendIndent(); stringBuilder.Append("Locals:"); foreach (ILocalSymbol local in region.Locals) { stringBuilder.Append($" [{local.ToTestDisplayString()}]"); } stringBuilder.AppendLine(); } if (!region.LocalFunctions.IsEmpty) { appendIndent(); stringBuilder.Append("Methods:"); foreach (IMethodSymbol method in region.LocalFunctions) { stringBuilder.Append($" [{method.ToTestDisplayString()}]"); } stringBuilder.AppendLine(); } } void enterRegions(ControlFlowRegion region, int firstBlockOrdinal) { if (region.FirstBlockOrdinal != firstBlockOrdinal) { Assert.Same(currentRegion, region); if (lastPrintedBlockIsInCurrentRegion) { stringBuilder.AppendLine(); } return; } enterRegions(region.EnclosingRegion, firstBlockOrdinal); currentRegion = region; lastPrintedBlockIsInCurrentRegion = true; switch (region.Kind) { case ControlFlowRegionKind.Filter: Assert.Empty(region.Locals); Assert.Empty(region.LocalFunctions); Assert.Equal(firstBlockOrdinal, region.EnclosingRegion.FirstBlockOrdinal); Assert.Same(region.ExceptionType, region.EnclosingRegion.ExceptionType); enterRegion($".filter {{{getRegionId(region)}}}"); break; case ControlFlowRegionKind.Try: Assert.Null(region.ExceptionType); Assert.Equal(firstBlockOrdinal, region.EnclosingRegion.FirstBlockOrdinal); enterRegion($".try {{{getRegionId(region.EnclosingRegion)}, {getRegionId(region)}}}"); break; case ControlFlowRegionKind.FilterAndHandler: enterRegion($".catch {{{getRegionId(region)}}} ({region.ExceptionType?.ToTestDisplayString() ?? "null"})"); break; case ControlFlowRegionKind.Finally: Assert.Null(region.ExceptionType); enterRegion($".finally {{{getRegionId(region)}}}"); break; case ControlFlowRegionKind.Catch: switch (region.EnclosingRegion.Kind) { case ControlFlowRegionKind.FilterAndHandler: Assert.Same(region.ExceptionType, region.EnclosingRegion.ExceptionType); enterRegion($".handler {{{getRegionId(region)}}}"); break; case ControlFlowRegionKind.TryAndCatch: enterRegion($".catch {{{getRegionId(region)}}} ({region.ExceptionType?.ToTestDisplayString() ?? "null"})"); break; default: Assert.False(true, $"Unexpected region kind {region.EnclosingRegion.Kind}"); break; } break; case ControlFlowRegionKind.LocalLifetime: Assert.Null(region.ExceptionType); Assert.False(region.Locals.IsEmpty && region.LocalFunctions.IsEmpty); enterRegion($".locals {{{getRegionId(region)}}}"); break; case ControlFlowRegionKind.TryAndCatch: case ControlFlowRegionKind.TryAndFinally: Assert.Empty(region.Locals); Assert.Empty(region.LocalFunctions); Assert.Null(region.ExceptionType); break; case ControlFlowRegionKind.StaticLocalInitializer: Assert.Null(region.ExceptionType); Assert.Empty(region.Locals); enterRegion($".static initializer {{{getRegionId(region)}}}"); break; case ControlFlowRegionKind.ErroneousBody: Assert.Null(region.ExceptionType); enterRegion($".erroneous body {{{getRegionId(region)}}}"); break; default: Assert.False(true, $"Unexpected region kind {region.Kind}"); break; } void enterRegion(string header) { appendLine(header); appendLine("{"); indent += 4; printLocals(region); } } void leaveRegions(ControlFlowRegion region, int lastBlockOrdinal) { if (region.LastBlockOrdinal != lastBlockOrdinal) { currentRegion = region; lastPrintedBlockIsInCurrentRegion = false; return; } string regionId = getRegionId(region); for (var i = 0; i < region.LocalFunctions.Length; i++) { var method = region.LocalFunctions[i]; appendLine(""); appendLine("{ " + method.ToTestDisplayString()); appendLine(""); var g = graph.GetLocalFunctionControlFlowGraph(method); localFunctionsMap.Add(method, g); Assert.Equal(OperationKind.LocalFunction, g.OriginalOperation.Kind); GetFlowGraph(stringBuilder, compilation, g, region, $"#{i}{regionId}", indent + 4); appendLine("}"); } switch (region.Kind) { case ControlFlowRegionKind.LocalLifetime: case ControlFlowRegionKind.Filter: case ControlFlowRegionKind.Try: case ControlFlowRegionKind.Finally: case ControlFlowRegionKind.FilterAndHandler: case ControlFlowRegionKind.StaticLocalInitializer: case ControlFlowRegionKind.ErroneousBody: indent -= 4; appendLine("}"); break; case ControlFlowRegionKind.Catch: switch (region.EnclosingRegion.Kind) { case ControlFlowRegionKind.FilterAndHandler: case ControlFlowRegionKind.TryAndCatch: goto endRegion; default: Assert.False(true, $"Unexpected region kind {region.EnclosingRegion.Kind}"); break; } break; endRegion: goto case ControlFlowRegionKind.Filter; case ControlFlowRegionKind.TryAndCatch: case ControlFlowRegionKind.TryAndFinally: break; default: Assert.False(true, $"Unexpected region kind {region.Kind}"); break; } leaveRegions(region.EnclosingRegion, lastBlockOrdinal); } void validateBranch(BasicBlock fromBlock, ControlFlowBranch branch) { if (branch.Destination == null) { Assert.Empty(branch.FinallyRegions); Assert.Empty(branch.LeavingRegions); Assert.Empty(branch.EnteringRegions); Assert.True(ControlFlowBranchSemantics.None == branch.Semantics || ControlFlowBranchSemantics.Throw == branch.Semantics || ControlFlowBranchSemantics.Rethrow == branch.Semantics || ControlFlowBranchSemantics.StructuredExceptionHandling == branch.Semantics || ControlFlowBranchSemantics.ProgramTermination == branch.Semantics || ControlFlowBranchSemantics.Error == branch.Semantics); return; } Assert.True(ControlFlowBranchSemantics.Regular == branch.Semantics || ControlFlowBranchSemantics.Return == branch.Semantics); Assert.True(branch.Destination.Predecessors.Contains(p => p.Source == fromBlock)); if (!branch.FinallyRegions.IsEmpty) { appendLine($" Finalizing:" + buildList(branch.FinallyRegions)); } ControlFlowRegion remainedIn1 = fromBlock.EnclosingRegion; if (!branch.LeavingRegions.IsEmpty) { appendLine($" Leaving:" + buildList(branch.LeavingRegions)); foreach (ControlFlowRegion r in branch.LeavingRegions) { Assert.Same(remainedIn1, r); remainedIn1 = r.EnclosingRegion; } } ControlFlowRegion remainedIn2 = branch.Destination.EnclosingRegion; if (!branch.EnteringRegions.IsEmpty) { appendLine($" Entering:" + buildList(branch.EnteringRegions)); for (int j = branch.EnteringRegions.Length - 1; j >= 0; j--) { ControlFlowRegion r = branch.EnteringRegions[j]; Assert.Same(remainedIn2, r); remainedIn2 = r.EnclosingRegion; } } Assert.Same(remainedIn1.EnclosingRegion, remainedIn2.EnclosingRegion); string buildList(ImmutableArray <ControlFlowRegion> list) { var builder = PooledObjects.PooledStringBuilder.GetInstance(); foreach (ControlFlowRegion r in list) { builder.Builder.Append($" {{{getRegionId(r)}}}"); } return(builder.ToStringAndFree()); } } void validateRoot(IOperation root) { visitor.Visit(root); Assert.Null(root.Parent); Assert.Null(((Operation)root).SemanticModel); Assert.True(CanBeInControlFlowGraph(root), $"Unexpected node kind OperationKind.{root.Kind}"); foreach (var operation in root.Descendants()) { visitor.Visit(operation); Assert.NotNull(operation.Parent); Assert.Null(((Operation)operation).SemanticModel); Assert.True(CanBeInControlFlowGraph(operation), $"Unexpected node kind OperationKind.{operation.Kind}"); } } void validateLocalsAndMethodsLifetime(BasicBlock block) { ISymbol[] localsOrMethodsInBlock = Enumerable.Concat(block.Operations, new[] { block.BranchValue }). Where(o => o != null). SelectMany(o => o.DescendantsAndSelf(). Select(node => { IMethodSymbol method; switch (node.Kind) { case OperationKind.LocalReference: return(((ILocalReferenceOperation)node).Local); case OperationKind.MethodReference: method = ((IMethodReferenceOperation)node).Method; return(method.MethodKind == MethodKind.LocalFunction ? method.OriginalDefinition : null); case OperationKind.Invocation: method = ((IInvocationOperation)node).TargetMethod; return(method.MethodKind == MethodKind.LocalFunction ? method.OriginalDefinition : null); default: return((ISymbol)null); } }). Where(s => s != null)). Distinct().ToArray(); if (localsOrMethodsInBlock.Length == 0) { return; } var localsAndMethodsInRegions = PooledHashSet <ISymbol> .GetInstance(); ControlFlowRegion region = block.EnclosingRegion; do { foreach (ILocalSymbol l in region.Locals) { Assert.True(localsAndMethodsInRegions.Add(l)); } foreach (IMethodSymbol m in region.LocalFunctions) { Assert.True(localsAndMethodsInRegions.Add(m)); } region = region.EnclosingRegion; }while (region != null); foreach (ISymbol l in localsOrMethodsInBlock) { Assert.False(localsAndMethodsInRegions.Add(l), $"Local/method without owning region {l.ToTestDisplayString()} in [{getBlockId(block)}]"); } localsAndMethodsInRegions.Free(); } string getBlockId(BasicBlock block) { return($"B{block.Ordinal}{idSuffix}"); } string getRegionId(ControlFlowRegion region) { return($"R{regionMap[region]}{idSuffix}"); } string getOperationTree(IOperation operation) { var walker = new OperationTreeSerializer(graph, currentRegion, idSuffix, anonymousFunctionsMap, compilation, operation, initialIndent: 8 + indent); walker.Visit(operation); return(walker.Builder.ToString()); } }
private static void ProcessBody <TSyntaxKind>( SemanticModel semanticModel, ImmutableArray <IDiagnosticAnalyzer> analyzers, ICodeBlockStartedAnalyzer[] bodyAnalyzers, ISymbol symbol, SyntaxNode syntax, CancellationToken cancellationToken, Action <Diagnostic> addDiagnostic, AnalyzerOptions analyzerOptions, bool continueOnError, Func <SyntaxNode, TSyntaxKind> getKind) { var endedAnalyzers = ArrayBuilder <ICodeBlockEndedAnalyzer> .GetInstance(); PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > nodeAnalyzersByKind = null; foreach (var a in bodyAnalyzers) { // Catch Exception from a.OnCodeBlockStarted ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { var analyzer = a.OnCodeBlockStarted(syntax, symbol, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); if (analyzer != null && analyzer != a) { endedAnalyzers.Add(analyzer); } }); } foreach (var nodeAnalyzer in endedAnalyzers.Concat(analyzers).OfType <ISyntaxNodeAnalyzer <TSyntaxKind> >()) { // Catch Exception from nodeAnalyzer.SyntaxKindsOfInterest try { foreach (var kind in nodeAnalyzer.SyntaxKindsOfInterest) { if (nodeAnalyzersByKind == null) { nodeAnalyzersByKind = PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > .GetInstance(); } ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (!nodeAnalyzersByKind.TryGetValue(kind, out analyzersForKind)) { nodeAnalyzersByKind.Add(kind, analyzersForKind = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance()); } analyzersForKind.Add(nodeAnalyzer); } } catch (Exception e) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(nodeAnalyzer, e)); } } if (nodeAnalyzersByKind != null) { foreach (var child in syntax.DescendantNodesAndSelf()) { ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (nodeAnalyzersByKind.TryGetValue(getKind(child), out analyzersForKind)) { foreach (var analyzer in analyzersForKind) { // Catch Exception from analyzer.AnalyzeNode ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { analyzer.AnalyzeNode(child, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); }); } } } foreach (var b in nodeAnalyzersByKind.Values) { b.Free(); } nodeAnalyzersByKind.Free(); } foreach (var a in endedAnalyzers.Concat(analyzers.OfType <ICodeBlockEndedAnalyzer>())) { // Catch Exception from a.OnCodeBlockEnded ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { a.OnCodeBlockEnded(syntax, symbol, semanticModel, addDiagnostic, analyzerOptions, cancellationToken); }); } endedAnalyzers.Free(); }
protected new void Free() { _dagNodeLabels.Free(); _switchArms.Free(); base.Free(); }
private async Task AnalyzeDeclaringReference(CompilationEvent.SymbolDeclared symbolEvent, SyntaxReference decl, Action <Diagnostic> addDiagnostic, CancellationToken cancellationToken) { var symbol = symbolEvent.Symbol; var syntax = await decl.GetSyntaxAsync(); var endedAnalyzers = ArrayBuilder <ICodeBlockEndedAnalyzer> .GetInstance(); endedAnalyzers.AddRange(CodeBlockEndedAnalyzers); var nodeAnalyzers = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance(); nodeAnalyzers.AddRange(Analyzers.OfType <ISyntaxNodeAnalyzer <TSyntaxKind> >()); foreach (var da in CodeBlockStartedAnalyzers) { // Catch Exception from da.OnCodeBlockStarted ExecuteAndCatchIfThrows(da, addDiagnostic, continueOnError, cancellationToken, () => { var blockStatefulAnalyzer = da.OnCodeBlockStarted(syntax, symbol, symbolEvent.SemanticModel(decl), addDiagnostic, cancellationToken); var endedAnalyzer = blockStatefulAnalyzer as ICodeBlockEndedAnalyzer; if (endedAnalyzer != null) { endedAnalyzers.Add(endedAnalyzer); } var nodeAnalyzer = blockStatefulAnalyzer as ISyntaxNodeAnalyzer <TSyntaxKind>; if (nodeAnalyzer != null) { nodeAnalyzers.Add(nodeAnalyzer); } }); } PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > nodeAnalyzersByKind = null; foreach (var nodeAnalyzer in nodeAnalyzers) { // Catch Exception from nodeAnalyzer.SyntaxKindsOfInterest try { foreach (var kind in nodeAnalyzer.SyntaxKindsOfInterest) { if (nodeAnalyzersByKind == null) { nodeAnalyzersByKind = PooledDictionary <TSyntaxKind, ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > > .GetInstance(); } ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (!nodeAnalyzersByKind.TryGetValue(kind, out analyzersForKind)) { nodeAnalyzersByKind.Add(kind, analyzersForKind = ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > .GetInstance()); } analyzersForKind.Add(nodeAnalyzer); } } catch (Exception e) { // Create a info diagnostic saying that the analyzer failed addDiagnostic(GetAnalyzerDiagnostic(nodeAnalyzer, e)); } } nodeAnalyzers.Free(); SemanticModel semanticModel = (nodeAnalyzersByKind != null || endedAnalyzers.Any()) ? symbolEvent.SemanticModel(decl) : null; if (nodeAnalyzersByKind != null) { semanticModel = symbolEvent.SemanticModel(decl); foreach (var child in syntax.DescendantNodesAndSelf()) { ArrayBuilder <ISyntaxNodeAnalyzer <TSyntaxKind> > analyzersForKind; if (nodeAnalyzersByKind.TryGetValue(GetKind(child), out analyzersForKind)) { foreach (var analyzer in analyzersForKind) { // Catch Exception from analyzer.AnalyzeNode ExecuteAndCatchIfThrows(analyzer, addDiagnostic, continueOnError, cancellationToken, () => { analyzer.AnalyzeNode(child, semanticModel, addDiagnostic, cancellationToken); }); } } } foreach (var b in nodeAnalyzersByKind.Values) { b.Free(); } nodeAnalyzersByKind.Free(); } foreach (var a in endedAnalyzers) { // Catch Exception from a.OnCodeBlockEnded ExecuteAndCatchIfThrows(a, addDiagnostic, continueOnError, cancellationToken, () => { a.OnCodeBlockEnded(syntax, symbol, semanticModel, addDiagnostic, cancellationToken); }); } endedAnalyzers.Free(); }
public void Free() { _temps.Free(); _map.Free(); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics); context.RegisterCompilationStartAction( (CompilationStartAnalysisContext compilationContext) => { TaintedDataConfig taintedDataConfig = TaintedDataConfig.GetOrCreate(compilationContext.Compilation); TaintedDataSymbolMap <SourceInfo> sourceInfoSymbolMap = taintedDataConfig.GetSourceSymbolMap(this.SinkKind); if (sourceInfoSymbolMap.IsEmpty) { return; } TaintedDataSymbolMap <SinkInfo> sinkInfoSymbolMap = taintedDataConfig.GetSinkSymbolMap(this.SinkKind); if (sinkInfoSymbolMap.IsEmpty) { return; } compilationContext.RegisterOperationBlockStartAction( operationBlockStartContext => { ISymbol owningSymbol = operationBlockStartContext.OwningSymbol; if (owningSymbol.IsConfiguredToSkipAnalysis(operationBlockStartContext.Options, TaintedDataEnteringSinkDescriptor, operationBlockStartContext.Compilation, operationBlockStartContext.CancellationToken)) { return; } PooledHashSet <IOperation> rootOperationsNeedingAnalysis = PooledHashSet <IOperation> .GetInstance(); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IPropertyReferenceOperation propertyReferenceOperation = (IPropertyReferenceOperation)operationAnalysisContext.Operation; IOperation rootOperation = operationAnalysisContext.Operation.GetRoot(); if (sourceInfoSymbolMap.IsSourceProperty(propertyReferenceOperation.Property)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(rootOperation); } } }, OperationKind.PropertyReference); operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IInvocationOperation invocationOperation = (IInvocationOperation)operationAnalysisContext.Operation; IOperation rootOperation = operationAnalysisContext.Operation.GetRoot(); PooledDictionary <PointsToCheck, ImmutableHashSet <string> > evaluateWithPointsToAnalysis = null; PooledDictionary <ValueContentCheck, ImmutableHashSet <string> > evaluateWithValueContentAnalysis = null; PointsToAnalysisResult pointsToAnalysisResult = null; ValueContentAnalysisResult valueContentAnalysisResult = null; if (rootOperation.TryGetEnclosingControlFlowGraph(out ControlFlowGraph cfg)) { pointsToAnalysisResult = PointsToAnalysis.TryGetOrComputeResult( cfg, owningSymbol, operationAnalysisContext.Options, WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation), InterproceduralAnalysisConfiguration.Create( operationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: operationAnalysisContext.CancellationToken), interproceduralAnalysisPredicateOpt: null); if (pointsToAnalysisResult == null) { return; } } if (sourceInfoSymbolMap.RequiresValueContentAnalysis) { valueContentAnalysisResult = ValueContentAnalysis.TryGetOrComputeResult( cfg, owningSymbol, operationAnalysisContext.Options, WellKnownTypeProvider.GetOrCreate(operationAnalysisContext.Compilation), InterproceduralAnalysisConfiguration.Create( operationAnalysisContext.Options, SupportedDiagnostics, defaultInterproceduralAnalysisKind: InterproceduralAnalysisKind.ContextSensitive, cancellationToken: operationAnalysisContext.CancellationToken), out var copyAnalysisResult, out pointsToAnalysisResult); if (valueContentAnalysisResult == null) { return; } } try { if (sourceInfoSymbolMap.IsSourceMethod( invocationOperation.TargetMethod, invocationOperation.Arguments, invocationOperation.Arguments.Select(o => pointsToAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(), invocationOperation.Arguments.Select(o => valueContentAnalysisResult[o.Kind, o.Syntax]).ToImmutableArray(), out _)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(rootOperation); } } } finally { evaluateWithPointsToAnalysis?.Free(); evaluateWithValueContentAnalysis?.Free(); } }, OperationKind.Invocation); if (taintedDataConfig.HasTaintArraySource(SinkKind)) { operationBlockStartContext.RegisterOperationAction( operationAnalysisContext => { IArrayInitializerOperation arrayInitializerOperation = (IArrayInitializerOperation)operationAnalysisContext.Operation; if (arrayInitializerOperation.GetAncestor <IArrayCreationOperation>(OperationKind.ArrayCreation)?.Type is IArrayTypeSymbol arrayTypeSymbol && sourceInfoSymbolMap.IsSourceConstantArrayOfType(arrayTypeSymbol)) { lock (rootOperationsNeedingAnalysis) { rootOperationsNeedingAnalysis.Add(operationAnalysisContext.Operation.GetRoot()); } } }, OperationKind.ArrayInitializer); } operationBlockStartContext.RegisterOperationBlockEndAction( operationBlockAnalysisContext => { try { lock (rootOperationsNeedingAnalysis) { if (!rootOperationsNeedingAnalysis.Any()) { return; } foreach (IOperation rootOperation in rootOperationsNeedingAnalysis) { if (!rootOperation.TryGetEnclosingControlFlowGraph(out var cfg)) { continue; } TaintedDataAnalysisResult taintedDataAnalysisResult = TaintedDataAnalysis.TryGetOrComputeResult( cfg, operationBlockAnalysisContext.Compilation, operationBlockAnalysisContext.OwningSymbol, operationBlockAnalysisContext.Options, TaintedDataEnteringSinkDescriptor, sourceInfoSymbolMap, taintedDataConfig.GetSanitizerSymbolMap(this.SinkKind), sinkInfoSymbolMap, operationBlockAnalysisContext.CancellationToken); if (taintedDataAnalysisResult == null) { return; } foreach (TaintedDataSourceSink sourceSink in taintedDataAnalysisResult.TaintedDataSourceSinks) { if (!sourceSink.SinkKinds.Contains(this.SinkKind)) { continue; } foreach (SymbolAccess sourceOrigin in sourceSink.SourceOrigins) { // Something like: // CA3001: Potential SQL injection vulnerability was found where '{0}' in method '{1}' may be tainted by user-controlled data from '{2}' in method '{3}'. Diagnostic diagnostic = Diagnostic.Create( this.TaintedDataEnteringSinkDescriptor, sourceSink.Sink.Location, additionalLocations: new Location[] { sourceOrigin.Location }, messageArgs: new object[] { sourceSink.Sink.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceSink.Sink.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.Symbol.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat), sourceOrigin.AccessingMethod.ToDisplayString(SymbolDisplayFormat.MinimallyQualifiedFormat) }); operationBlockAnalysisContext.ReportDiagnostic(diagnostic); } } } } } finally { rootOperationsNeedingAnalysis.Free(); } }); }); }); }
protected new void Free() { _dagNodeLabels.Free(); base.Free(); }