public static ImmutableDictionary <IParameterSymbol, SyntaxNode> GetOrComputeHazardousParameterUsages(
            IOperation topmostBlock,
            Compilation compilation,
            ISymbol owningSymbol,
            bool pessimisticAnalysis = true)
        {
            Debug.Assert(topmostBlock != null);

            var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilation);

            ParameterValidationResultWithHazardousUsages GetOrComputeLocationAnalysisResultForInvokedMethod(IBlockOperation methodTopmostBlock, IMethodSymbol method)
            {
                // getOrComputeLocationAnalysisResultOpt = null, so we do interprocedural analysis only one level down.
                Debug.Assert(methodTopmostBlock != null);
                return(GetOrComputeResult(methodTopmostBlock, method, wellKnownTypeProvider, getOrComputeLocationAnalysisResultOpt: null, pessimisticAnalysis: pessimisticAnalysis));
            };

            ParameterValidationResultWithHazardousUsages result = GetOrComputeResult(topmostBlock, owningSymbol, wellKnownTypeProvider, GetOrComputeLocationAnalysisResultForInvokedMethod, pessimisticAnalysis);

            return(result.HazardousParameterUsages);
        }
예제 #2
0
            public override ParameterValidationAbstractValue VisitArgumentCore(IArgumentOperation operation, object argument)
            {
                var value = base.VisitArgumentCore(operation, argument);

                // Arguments to validation methods must be marked as validated.
                var notValidatedLocations = GetNotValidatedLocations(operation);

                if (notValidatedLocations.Any())
                {
                    if (_getOrComputeLocationAnalysisResultOpt != null)
                    {
                        IMethodSymbol targetMethod = null;
                        if (operation.Parent is IInvocationOperation invocation)
                        {
                            targetMethod = invocation.TargetMethod;
                        }
                        else if (operation.Parent is IObjectCreationOperation objectCreation)
                        {
                            targetMethod = objectCreation.Constructor;
                        }

                        if (targetMethod != null &&
                            targetMethod != OwningSymbol)
                        {
                            if (targetMethod.ContainingType.SpecialType == SpecialType.System_String)
                            {
                                if (targetMethod.IsStatic &&
                                    targetMethod.Name.StartsWith("IsNull", StringComparison.Ordinal) &&
                                    targetMethod.Parameters.Length == 1)
                                {
                                    // string.IsNullOrXXX check.
                                    SetAbstractValue(notValidatedLocations, ParameterValidationAbstractValue.Validated);
                                }
                            }
                            else if (WellKnownTypeProvider.Exception != null && targetMethod.ContainingType.DerivesFrom(WellKnownTypeProvider.Exception))
                            {
                                // FxCop compat: special cases handled by FxCop.
                                //  1. First argument of type System.Runtime.Serialization.SerializationInfo to System.Exception.GetObjectData or its override is validated.
                                //  2. First argument of type System.Runtime.Serialization.SerializationInfo to constructor of System.Exception or its subtype is validated.
                                if (operation.Parameter.Type == WellKnownTypeProvider.SerializationInfo)
                                {
                                    switch (targetMethod.MethodKind)
                                    {
                                    case MethodKind.Ordinary:
                                        if (targetMethod.Name.Equals("GetObjectData", StringComparison.OrdinalIgnoreCase))
                                        {
                                            SetAbstractValue(notValidatedLocations, ParameterValidationAbstractValue.Validated);
                                        }
                                        break;

                                    case MethodKind.Constructor:
                                        SetAbstractValue(notValidatedLocations, ParameterValidationAbstractValue.Validated);
                                        break;
                                    }
                                }
                            }
                            else
                            {
                                var methodTopmostBlock = targetMethod.GetTopmostOperationBlock(WellKnownTypeProvider.Compilation);
                                if (methodTopmostBlock != null)
                                {
                                    ParameterValidationResultWithHazardousUsages invokedMethodAnalysisResult = _getOrComputeLocationAnalysisResultOpt(methodTopmostBlock, targetMethod);
                                    var invokedMethodLocationAnalysisResult     = invokedMethodAnalysisResult.ParameterValidationAnalysisResult;
                                    var hazardousParameterUsagesInInvokedMethod = invokedMethodAnalysisResult.HazardousParameterUsages;
                                    if (invokedMethodLocationAnalysisResult != null)
                                    {
                                        Debug.Assert(hazardousParameterUsagesInInvokedMethod != null);

                                        // Non-validated argument passed to private/internal methods might be hazardous.
                                        if (hazardousParameterUsagesInInvokedMethod.ContainsKey(operation.Parameter))
                                        {
                                            if (_hazardousParameterUsageBuilderOpt != null && !targetMethod.IsExternallyVisible())
                                            {
                                                HandlePotentiallyHazardousOperation(operation, notValidatedLocations);
                                            }
                                        }
                                        else if (!targetMethod.IsVirtual && !targetMethod.IsOverride)
                                        {
                                            // Check if this is a non-virtual non-override method that validates the argument.
                                            BasicBlock invokedMethodExitBlock = invokedMethodLocationAnalysisResult.ControlFlowGraph.Exit;
                                            foreach (var kvp in invokedMethodLocationAnalysisResult[invokedMethodExitBlock].OutputData)
                                            {
                                                AbstractLocation parameterLocation = kvp.Key;
                                                ParameterValidationAbstractValue parameterValue = kvp.Value;
                                                Debug.Assert(parameterLocation.SymbolOpt is IParameterSymbol invokedMethodParameter && invokedMethodParameter.ContainingSymbol == targetMethod);

                                                // Check if the matching parameter was validated by the invoked method.
                                                if ((IParameterSymbol)parameterLocation.SymbolOpt == operation.Parameter &&
                                                    parameterValue == ParameterValidationAbstractValue.Validated)
                                                {
                                                    SetAbstractValue(notValidatedLocations, ParameterValidationAbstractValue.Validated);
                                                    break;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                return(value);
            }