Ejemplo n.º 1
0
        protected override ParameterValidationAnalysisResult ToResult(
            ParameterValidationAnalysisContext analysisContext,
            DataFlowAnalysisResult <ParameterValidationBlockAnalysisResult, ParameterValidationAbstractValue> dataFlowAnalysisResult)
        {
            analysisContext = analysisContext.WithTrackHazardousParameterUsages();
            var newOperationVisitor = new ParameterValidationDataFlowOperationVisitor(analysisContext);

            foreach (var block in analysisContext.ControlFlowGraph.Blocks)
            {
                var data = new ParameterValidationAnalysisData(dataFlowAnalysisResult[block].Data);
                data = Flow(newOperationVisitor, block, data);

                if (block.FallThroughSuccessor != null)
                {
                    var fallThroughData = block.ConditionalSuccessor != null?AnalysisDomain.Clone(data) : data;

                    _ = FlowBranch(newOperationVisitor, block.FallThroughSuccessor, fallThroughData);
                }

                if (block.ConditionalSuccessor != null)
                {
                    _ = FlowBranch(newOperationVisitor, block.ConditionalSuccessor, data);
                }
            }

            return(new ParameterValidationAnalysisResult(dataFlowAnalysisResult, newOperationVisitor.HazardousParameterUsages));
        }
        private TAnalysisResult Run(TAnalysisContext analysisContext)
        {
            var cfg              = analysisContext.ControlFlowGraph;
            var resultBuilder    = new DataFlowAnalysisResultBuilder <TAnalysisData>();
            var uniqueSuccessors = PooledHashSet <BasicBlock> .GetInstance();

            var finallyBlockSuccessorsMap = PooledDictionary <int, List <BranchWithInfo> > .GetInstance();

            var catchBlockInputDataMap = PooledDictionary <ControlFlowRegion, TAnalysisData> .GetInstance();

            var inputDataFromInfeasibleBranchesMap = PooledDictionary <int, TAnalysisData> .GetInstance();

            var unreachableBlocks = PooledHashSet <int> .GetInstance();

            var worklist = new SortedSet <int>();
            var pendingBlocksNeedingAtLeastOnePass = new SortedSet <int>(cfg.Blocks.Select(b => b.Ordinal));

            // Map from Ordinal -> (Ordinal, ControlFlowConditionKind)? with following semantics:
            //  1. Key is a valid basic block ordinal.
            //  2. Value tuple indicates the following:
            //      a. Non-null tuple value: Indicates a unique branch entering the block, with following tuple values:
            //         i. Ordinal of the single unique block from which analysis data has been transferred into the Key,
            //            which is normally a predecessor but can be a non-predecessor block for finally/catch.
            //         ii. ControlFlowConditionKind indicating the nature of branch, i.e. conditional or fall through.
            //             This is required as CFG can have both conditional and fall through branches
            //             with the same source and destination blocks.
            //      b. Null tuple value: Block had analysis data flowing into it from multiple different branches.
            //
            //  This map allows us to optimize the number of merge operations. We can avoid merge and directly
            //  overwrite analysis data into a successor if successor block has no entry or entry with non-null tuple value
            //  with the matching input branch.
            var blockToUniqueInputFlowMap = PooledDictionary <int, (int Ordinal, ControlFlowConditionKind BranchKind)?> .GetInstance();

            // Map from basic block ordinals that are destination of back edge(s) to the minimum block ordinal that dominates it,
            // i.e. for every '{key, value}' pair in the dictionary, 'key' is the destination of at least one back edge
            // and 'value' is the minimum ordinal such that there is no back edge to 'key' from any basic block with ordinal > 'value'.
            var loopRangeMap = PooledDictionary <int, int> .GetInstance();

            ComputeLoopRangeMap(cfg, loopRangeMap);

            TAnalysisData normalPathsExitBlockData = null, exceptionPathsExitBlockDataOpt = null;

            try
            {
                // Add each basic block to the result.
                foreach (var block in cfg.Blocks)
                {
                    resultBuilder.Add(block);
                }

                var entry = cfg.GetEntry();

                // Initialize the input of the entry block.
                // For context sensitive inter-procedural analysis, use the provided initial analysis data.
                // Otherwise, initialize with the default bottom value of the analysis domain.
                var initialAnalysisDataOpt = analysisContext.InterproceduralAnalysisDataOpt?.InitialAnalysisData;
                UpdateInput(resultBuilder, entry, GetClonedAnalysisDataOrEmptyData(initialAnalysisDataOpt));

                // Add the block to the worklist.
                worklist.Add(entry.Ordinal);

                RunCore(cfg, worklist, pendingBlocksNeedingAtLeastOnePass, initialAnalysisDataOpt, resultBuilder,
                        uniqueSuccessors, finallyBlockSuccessorsMap, catchBlockInputDataMap, inputDataFromInfeasibleBranchesMap,
                        blockToUniqueInputFlowMap, loopRangeMap, exceptionPathsAnalysisPostPass: false);
                normalPathsExitBlockData = resultBuilder.ExitBlockOutputData;

                if (analysisContext.ExceptionPathsAnalysis)
                {
                    // Clone and save exit block data
                    normalPathsExitBlockData = AnalysisDomain.Clone(normalPathsExitBlockData);

                    OperationVisitor.ExecutingExceptionPathsAnalysisPostPass = true;
                    foreach (var block in cfg.Blocks)
                    {
                        blockToUniqueInputFlowMap[block.Ordinal] = null;

                        // Skip entry block analysis.
                        if (block.Kind == BasicBlockKind.Entry)
                        {
                            continue;
                        }

                        if (block.IsReachable)
                        {
                            worklist.Add(block.Ordinal);
                        }
                        else
                        {
                            pendingBlocksNeedingAtLeastOnePass.Add(block.Ordinal);
                        }
                    }

                    RunCore(cfg, worklist, pendingBlocksNeedingAtLeastOnePass, initialAnalysisDataOpt, resultBuilder, uniqueSuccessors,
                            finallyBlockSuccessorsMap, catchBlockInputDataMap, inputDataFromInfeasibleBranchesMap,
                            blockToUniqueInputFlowMap, loopRangeMap, exceptionPathsAnalysisPostPass: true);
                    exceptionPathsExitBlockDataOpt = resultBuilder.ExitBlockOutputData;
                    OperationVisitor.ExecutingExceptionPathsAnalysisPostPass = false;
                }

                var mergedDataForUnhandledThrowOperationsOpt = OperationVisitor.GetMergedDataForUnhandledThrowOperations();

                var dataflowAnalysisResult = resultBuilder.ToResult(ToBlockResult, OperationVisitor.GetStateMap(),
                                                                    OperationVisitor.GetPredicateValueKindMap(), OperationVisitor.GetReturnValueAndPredicateKind(), OperationVisitor.InterproceduralResultsMap,
                                                                    resultBuilder.EntryBlockOutputData, normalPathsExitBlockData, exceptionPathsExitBlockDataOpt,
                                                                    mergedDataForUnhandledThrowOperationsOpt, OperationVisitor.AnalysisDataForUnhandledThrowOperations, cfg, OperationVisitor.ValueDomain.UnknownOrMayBeValue);
                return(ToResult(analysisContext, dataflowAnalysisResult));
            }
            finally
            {
                resultBuilder.Dispose();
                uniqueSuccessors.Free();
                finallyBlockSuccessorsMap.Free();
                catchBlockInputDataMap.Values.Dispose();
                catchBlockInputDataMap.Free();
                inputDataFromInfeasibleBranchesMap.Values.Dispose();
                inputDataFromInfeasibleBranchesMap.Free();
                unreachableBlocks.Free();
                blockToUniqueInputFlowMap.Free();
                loopRangeMap.Free();
            }
        }
Ejemplo n.º 3
0
        private DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> Run(ControlFlowGraph cfg)
        {
            var resultBuilder = new DataFlowAnalysisResultBuilder <TAnalysisData>();

            // Add each basic block to the result.
            foreach (var block in cfg.Blocks)
            {
                resultBuilder.Add(block);
            }

            var worklist = new Queue <BasicBlock>();
            var entry    = GetEntry(cfg);

            // Initialize the output of the initial block
            // with the default abstract value of the domain.
            UpdateOutput(resultBuilder, entry, AnalysisDomain.Bottom);

            // Add all successor blocks of the initial
            // block to be processed.
            EnqueueRange(worklist, GetSuccessors(entry));

            while (worklist.Count > 0)
            {
                // Get the next block to process
                // and its associated result.
                var block = worklist.Dequeue();

                // Get the outputs of all predecessor blocks of the current block.
                var inputs = GetPredecessors(block).Select(b => GetOutput(resultBuilder[b]));

                // Merge all the outputs to get the new input of the current block.
                var input = AnalysisDomain.Merge(inputs);

                // Compare the previous input with the new input.
                var compare = AnalysisDomain.Compare(GetInput(resultBuilder[block]), input);

                // The newly computed abstract values for each basic block
                // must be always greater or equal than the previous value
                // to ensure termination.
                Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                // Is old input value < new input value ?
                if (compare < 0)
                {
                    // The newly computed value is greater than the previous value,
                    // so we need to update the current block result's
                    // input values with the new ones.
                    UpdateInput(resultBuilder, block, AnalysisDomain.Clone(input));

                    // Flow the new input through the block to get a new output.
                    var output = Flow(block, input);

                    // Compare the previous output with the new output.
                    compare = AnalysisDomain.Compare(GetOutput(resultBuilder[block]), output);

                    // The newly computed abstract values for each basic block
                    // must be always greater or equal than the previous value
                    // to ensure termination.
                    Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                    // Is old output value < new output value ?
                    if (compare < 0)
                    {
                        // The newly computed value is greater than the previous value,
                        // so we need to update the current block result's
                        // output values with the new ones.
                        UpdateOutput(resultBuilder, block, output);

                        // Since the new output value is different than the previous one,
                        // we need to propagate it to all the successor blocks of the current block.
                        EnqueueRange(worklist, GetSuccessors(block));
                    }
                }
            }

            return(resultBuilder.ToResult(ToResult, OperationVisitor.GetStateMap()));
        }
Ejemplo n.º 4
0
        private DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> Run(ControlFlowGraph cfg, DataFlowAnalysisResult <TAnalysisResult, TAbstractAnalysisValue> seedResultOpt)
        {
            var resultBuilder = new DataFlowAnalysisResultBuilder <TAnalysisData>();

            // Add each basic block to the result.
            foreach (var block in cfg.Blocks)
            {
                resultBuilder.Add(block);
            }

            var worklist = new Queue <BasicBlock>();
            var pendingBlocksNeedingAtLeastOnePass = new HashSet <BasicBlock>(cfg.Blocks);
            var entry = GetEntry(cfg);

            // Are we computing the analysis data from scratch?
            if (seedResultOpt == null)
            {
                // Initialize the input of the initial block
                // with the default abstract value of the domain.
                UpdateInput(resultBuilder, entry, AnalysisDomain.Bottom);
            }
            else
            {
                // Initialize the input and output of every block
                // with the previously computed value.
                foreach (var block in cfg.Blocks)
                {
                    UpdateInput(resultBuilder, block, GetInputData(seedResultOpt[block]));
                }
            }

            // Add the block to the worklist.
            worklist.Enqueue(entry);

            while (worklist.Count > 0 || pendingBlocksNeedingAtLeastOnePass.Count > 0)
            {
                // Get the next block to process
                // and its associated result.
                var block = worklist.Count > 0 ? worklist.Dequeue() : pendingBlocksNeedingAtLeastOnePass.ElementAt(0);
                var needsAtLeastOnePass = pendingBlocksNeedingAtLeastOnePass.Remove(block);

                // Get the outputs of all predecessor blocks of the current block.
                var inputs = GetPredecessors(block).Select(b => GetOutput(resultBuilder[b]));

                // Merge all the outputs to get the new input of the current block.
                var input = AnalysisDomain.Merge(inputs);

                // Merge might return one of the original input values if only one of them is a valid non-null value.
                if (inputs.Any(i => ReferenceEquals(input, i)))
                {
                    input = AnalysisDomain.Clone(input);
                }

                // Temporary workaround due to lack of *real* CFG
                // TODO: Remove the below if statement once we move to compiler's CFG
                // https://github.com/dotnet/roslyn-analyzers/issues/1567
                if (block.Kind == BasicBlockKind.Exit &&
                    OperationVisitor.MergedAnalysisDataAtReturnStatements != null)
                {
                    input = AnalysisDomain.Merge(input, OperationVisitor.MergedAnalysisDataAtReturnStatements);
                }

                // Compare the previous input with the new input.
                if (!needsAtLeastOnePass)
                {
                    int compare = AnalysisDomain.Compare(GetInput(resultBuilder[block]), input);

                    // The newly computed abstract values for each basic block
                    // must be always greater or equal than the previous value
                    // to ensure termination.
                    Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                    // Is old input value >= new input value
                    if (compare >= 0)
                    {
                        continue;
                    }
                }

                // The newly computed value is greater than the previous value,
                // so we need to update the current block result's
                // input values with the new ones.
                UpdateInput(resultBuilder, block, AnalysisDomain.Clone(input));

                // Flow the new input through the block to get a new output.
                var output = Flow(OperationVisitor, block, input);

                // Compare the previous output with the new output.
                if (!needsAtLeastOnePass)
                {
                    int compare = AnalysisDomain.Compare(GetOutput(resultBuilder[block]), output);

                    // The newly computed abstract values for each basic block
                    // must be always greater or equal than the previous value
                    // to ensure termination.
                    Debug.Assert(compare <= 0, "The newly computed abstract value must be greater or equal than the previous one.");

                    // Is old output value >= new output value ?
                    if (compare >= 0)
                    {
                        continue;
                    }
                }

                // The newly computed value is greater than the previous value,
                // so we need to update the current block result's
                // output values with the new ones.
                UpdateOutput(resultBuilder, block, output);

                // Since the new output value is different than the previous one,
                // we need to propagate it to all the successor blocks of the current block.
                EnqueueRange(worklist, GetSuccessors(block));
            }

            return(resultBuilder.ToResult(ToResult, OperationVisitor.GetStateMap(),
                                          OperationVisitor.GetPredicateValueKindMap(), OperationVisitor.GetMergedDataForUnhandledThrowOperations(),
                                          cfg, OperationVisitor.ValueDomain.UnknownOrMayBeValue));
        }