예제 #1
0
        /// <summary>
        /// Analyzes the ownership of the given-up symbol
        /// in the candidate callee.
        /// </summary>
        /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param>
        /// <param name="calleeSummary">MethodSummary</param>
        /// <param name="call">ExpressionSyntax</param>
        /// <param name="statement">Statement</param>
        /// <param name="machine">StateMachine</param>
        /// <param name="model">SemanticModel</param>
        /// <param name="trace">TraceInfo</param>
        protected override void AnalyzeOwnershipInCandidateCallee(GivenUpOwnershipSymbol givenUpSymbol,
                                                                  MethodSummary calleeSummary, ExpressionSyntax call, Statement statement,
                                                                  StateMachine machine, SemanticModel model, TraceInfo trace)
        {
            ArgumentListSyntax argumentList = base.AnalysisContext.GetArgumentList(call);

            if (argumentList == null)
            {
                return;
            }

            for (int idx = 0; idx < argumentList.Arguments.Count; idx++)
            {
                var argIdentifier = base.AnalysisContext.GetRootIdentifier(
                    argumentList.Arguments[idx].Expression);
                if (argIdentifier == null)
                {
                    continue;
                }

                ISymbol argSymbol = model.GetSymbolInfo(argIdentifier).Symbol;
                if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(argSymbol,
                                                                       givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement))
                {
                    if (calleeSummary.SideEffectsInfo.FieldFlowParamIndexes.Any(v => v.Value.Contains(idx) &&
                                                                                base.IsFieldAccessedInSuccessor(v.Key, statement.Summary, machine)))
                    {
                        AnalysisErrorReporter.ReportGivenUpFieldOwnershipError(trace, argSymbol);
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Analyzes the ownership of the given-up symbol
        /// in the call.
        /// </summary>
        /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param>
        /// <param name="call">ExpressionSyntax</param>
        /// <param name="statement">Statement</param>
        /// <param name="machine">StateMachine</param>
        /// <param name="model">SemanticModel</param>
        /// <param name="trace">TraceInfo</param>
        /// <returns>Set of return symbols</returns>
        protected HashSet <ISymbol> AnalyzeOwnershipInCall(GivenUpOwnershipSymbol givenUpSymbol,
                                                           ExpressionSyntax call, Statement statement, StateMachine machine,
                                                           SemanticModel model, TraceInfo trace)
        {
            var potentialReturnSymbols = new HashSet <ISymbol>();

            var invocation  = call as InvocationExpressionSyntax;
            var objCreation = call as ObjectCreationExpressionSyntax;

            if ((invocation == null && objCreation == null))
            {
                return(potentialReturnSymbols);
            }

            TraceInfo callTrace = new TraceInfo();

            callTrace.Merge(trace);
            callTrace.AddErrorTrace(call);

            var callSymbol = model.GetSymbolInfo(call).Symbol;

            if (callSymbol == null)
            {
                base.ErrorReporter.ReportExternalInvocation(callTrace);
                return(potentialReturnSymbols);
            }

            if (callSymbol.ContainingType.ToString().Equals("Microsoft.PSharp.Machine"))
            {
                this.AnalyzeOwnershipInGivesUpCall(givenUpSymbol, invocation,
                                                   statement, machine, model, callTrace);
                return(potentialReturnSymbols);
            }

            if (SymbolFinder.FindSourceDefinitionAsync(callSymbol,
                                                       this.AnalysisContext.Solution).Result == null)
            {
                base.ErrorReporter.ReportExternalInvocation(callTrace);
                return(potentialReturnSymbols);
            }

            var candidateSummaries = MethodSummary.GetCachedSummaries(callSymbol, statement);

            foreach (var candidateSummary in candidateSummaries)
            {
                this.AnalyzeOwnershipInCandidateCallee(givenUpSymbol, candidateSummary,
                                                       call, statement, machine, model, callTrace);

                if (invocation != null)
                {
                    var resolvedReturnSymbols = candidateSummary.GetResolvedReturnSymbols(invocation, model);
                    foreach (var resolvedReturnSymbol in resolvedReturnSymbols)
                    {
                        potentialReturnSymbols.Add(resolvedReturnSymbol);
                    }
                }
            }

            return(potentialReturnSymbols);
        }
예제 #3
0
        /// <summary>
        /// Computes the 'gives_up' set for the given argument.
        /// </summary>
        /// <param name="arg">Argument</param>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="summary">MethodSummary</param>
        private static void ComputeGivesUpSetForArgument(ExpressionSyntax arg, ControlFlowGraphNode cfgNode,
                                                         MethodSummary summary)
        {
            var model = AnalysisContext.Compilation.GetSemanticModel(arg.SyntaxTree);

            if (arg is IdentifierNameSyntax || arg is MemberAccessExpressionSyntax)
            {
                for (int idx = 0; idx < summary.Method.ParameterList.Parameters.Count; idx++)
                {
                    if (Utilities.IsTypeAllowedToBeSend(summary.Method.ParameterList.Parameters[idx].Type, model))
                    {
                        continue;
                    }

                    var paramSymbol = model.GetDeclaredSymbol(summary.Method.ParameterList.Parameters[idx]);
                    if (DataFlowAnalysis.FlowsFromTarget(arg, paramSymbol, summary.Node.SyntaxNodes.First(),
                                                         summary.Node, cfgNode.SyntaxNodes.First(), cfgNode, model))
                    {
                        summary.GivesUpSet.Add(idx);
                    }
                }
            }
            else if (arg is ObjectCreationExpressionSyntax)
            {
                var payload = arg as ObjectCreationExpressionSyntax;
                foreach (var item in payload.ArgumentList.Arguments)
                {
                    MethodSummaryAnalysis.ComputeGivesUpSetForArgument(item.Expression,
                                                                       cfgNode, summary);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Tries to compute the 'gives_up' set of indexes for the given control flow graph node.
        /// If the node does not contain a 'Send' operation, then it returns false.
        /// </summary>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean value</returns>
        private bool TryComputeGivesUpSetForSendControlFlowGraphNode(ControlFlowGraphNode cfgNode,
                                                                     MethodSummary summary)
        {
            var sendExpr = cfgNode.SyntaxNodes.First() as ExpressionStatementSyntax;

            if (sendExpr == null)
            {
                return(false);
            }

            var send = sendExpr.Expression as InvocationExpressionSyntax;

            if (send == null || !((send.Expression is MemberAccessExpressionSyntax) ||
                                  (send.Expression is IdentifierNameSyntax)))
            {
                return(false);
            }

            if (((send.Expression is MemberAccessExpressionSyntax) &&
                 !(send.Expression as MemberAccessExpressionSyntax).
                 Name.Identifier.ValueText.Equals("Send")) ||
                ((send.Expression is IdentifierNameSyntax) &&
                 !(send.Expression as IdentifierNameSyntax).
                 Identifier.ValueText.Equals("Send")))
            {
                return(false);
            }

            if (send.ArgumentList.Arguments[1].Expression is ObjectCreationExpressionSyntax)
            {
                var objCreation = send.ArgumentList.Arguments[1].Expression
                                  as ObjectCreationExpressionSyntax;
                foreach (var arg in objCreation.ArgumentList.Arguments)
                {
                    this.ComputeGivesUpSetForArgument(arg.Expression, cfgNode, summary);
                }
            }
            else if (send.ArgumentList.Arguments[1].Expression is BinaryExpressionSyntax &&
                     send.ArgumentList.Arguments[1].Expression.IsKind(SyntaxKind.AsExpression))
            {
                var binExpr = send.ArgumentList.Arguments[1].Expression
                              as BinaryExpressionSyntax;
                if ((binExpr.Left is IdentifierNameSyntax) || (binExpr.Left is MemberAccessExpressionSyntax))
                {
                    this.ComputeGivesUpSetForArgument(binExpr.Left, cfgNode, summary);
                }
                else if (binExpr.Left is InvocationExpressionSyntax)
                {
                    var invocation = binExpr.Left as InvocationExpressionSyntax;
                    for (int i = 1; i < invocation.ArgumentList.Arguments.Count; i++)
                    {
                        this.ComputeGivesUpSetForArgument(invocation.ArgumentList.
                                                          Arguments[i].Expression, cfgNode, summary);
                    }
                }
            }

            return(true);
        }
예제 #5
0
        /// <summary>
        /// Constructs the node using information from the given state transitions
        /// and action bindings.
        /// </summary>
        /// <param name="stateTransitions">State transitions</param>
        /// <param name="actionBindings">Action bindings</param>
        /// <param name="visited">Already visited nodes</param>
        private void Construct(Dictionary <ClassDeclarationSyntax, HashSet <ClassDeclarationSyntax> > stateTransitions,
                               Dictionary <ClassDeclarationSyntax, HashSet <MethodDeclarationSyntax> > actionBindings,
                               HashSet <StateTransitionGraphNode> visited)
        {
            visited.Add(this);

            foreach (var method in this.State.ChildNodes().OfType <MethodDeclarationSyntax>())
            {
                var summary = MethodSummary.Factory.Summarize(method);
                if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) &&
                    method.Identifier.ValueText.Equals("OnEntry"))
                {
                    this.OnEntry = summary;
                }
                else if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) &&
                         method.Identifier.ValueText.Equals("OnExit"))
                {
                    this.OnExit = summary;
                }
            }

            var actions = new HashSet <MethodDeclarationSyntax>();

            if (actionBindings.ContainsKey(this.State))
            {
                actions = actionBindings[this.State];
            }

            foreach (var action in actions)
            {
                var actionSummary = MethodSummary.Factory.Summarize(action);
                this.Actions.Add(actionSummary);
            }

            var transitions = new HashSet <ClassDeclarationSyntax>();

            if (stateTransitions.ContainsKey(this.State))
            {
                transitions = stateTransitions[this.State];
            }

            foreach (var successorState in transitions)
            {
                var successor = visited.FirstOrDefault(v => v.State.Equals(successorState));
                if (successor != null)
                {
                    this.ISuccessors.Add(successor);
                    successor.IPredecessors.Add(this);
                }
                else
                {
                    successor = new StateTransitionGraphNode(successorState, this.Machine);
                    this.ISuccessors.Add(successor);
                    successor.IPredecessors.Add(this);
                    successor.Construct(stateTransitions, actionBindings, visited);
                }
            }
        }
예제 #6
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="summary">MethodSummary</param>
 internal ControlFlowGraphNode(MethodSummary summary)
 {
     this.Id             = ControlFlowGraphNode.IdCounter++;
     this.Summary        = summary;
     this.SyntaxNodes    = new List <SyntaxNode>();
     this.IPredecessors  = new HashSet <ControlFlowGraphNode>();
     this.ISuccessors    = new HashSet <ControlFlowGraphNode>();
     this.IsGivesUpNode  = false;
     this.IsJumpNode     = false;
     this.IsLoopHeadNode = false;
 }
예제 #7
0
        /// <summary>
        /// Returns all the successor summaries.
        /// </summary>
        /// <param name="summary">MethodSummary</param>
        /// <returns>MethodSummarys</returns>
        internal ISet <MethodSummary> GetSuccessorSummaries(MethodSummary summary)
        {
            var summaries = new HashSet <MethodSummary>();

            if (this.MethodSummaries.Count == 0)
            {
                return(summaries);
            }

            var fromStates = new HashSet <MachineState>();

            foreach (var state in this.MachineStates)
            {
                var summaryActions = state.MachineActions.FindAll(action
                                                                  => action.MethodDeclaration.Equals(summary.Method));
                if (summaryActions.Count == 0)
                {
                    continue;
                }

                foreach (var summaryAction in summaryActions)
                {
                    if (!(summaryAction is OnExitMachineAction))
                    {
                        summaries.UnionWith(state.MachineActions.FindAll(action
                                                                         => action is OnEventDoMachineAction || action is OnEventGotoMachineAction ||
                                                                         action is OnEventPushMachineAction || action is OnExitMachineAction).
                                            Select(action => action.MethodDeclaration).
                                            Select(method => this.MethodSummaries[method]));
                    }
                }

                fromStates.Add(state);
            }

            foreach (var state in fromStates)
            {
                foreach (var successor in state.GetSuccessorStates())
                {
                    summaries.UnionWith(successor.MachineActions.FindAll(action
                                                                         => action is OnEntryMachineAction || action is OnEventDoMachineAction ||
                                                                         action is OnEventGotoMachineAction || action is OnEventPushMachineAction ||
                                                                         action is OnExitMachineAction).
                                        Select(action => action.MethodDeclaration).
                                        Select(method => this.MethodSummaries[method]));
                }
            }

            return(summaries);
        }
예제 #8
0
        /// <summary>
        /// Computes the summary for the given method.
        /// </summary>
        /// <param name="method">Method</param>
        /// <param name="machine">Machine</param>
        /// <param name="state">State</param>
        private static void ComputeSummaryForMethod(MethodDeclarationSyntax method,
                                                    ClassDeclarationSyntax machine, ClassDeclarationSyntax state)
        {
            List <InvocationExpressionSyntax> givesUpSources = new List <InvocationExpressionSyntax>();

            foreach (var call in method.DescendantNodes().OfType <InvocationExpressionSyntax>())
            {
                var model = AnalysisContext.Compilation.GetSemanticModel(call.SyntaxTree);

                var callSymbol = model.GetSymbolInfo(call).Symbol;
                if (callSymbol == null)
                {
                    continue;
                }

                var definition = SymbolFinder.FindSourceDefinitionAsync(callSymbol, ProgramInfo.Solution).Result;
                if (definition == null)
                {
                    continue;
                }

                var callee       = Utilities.GetCallee(call);
                var calleeMethod = definition.DeclaringSyntaxReferences.First().GetSyntax()
                                   as BaseMethodDeclarationSyntax;

                if (Utilities.IsSourceOfGivingUpOwnership(call, model, callee) ||
                    AnalysisContext.Summaries.ContainsKey(calleeMethod))
                {
                    givesUpSources.Add(call);
                }
                else if (machine.ChildNodes().OfType <BaseMethodDeclarationSyntax>().Contains(calleeMethod) &&
                         !AnalysisContext.Summaries.ContainsKey(calleeMethod) &&
                         !calleeMethod.Modifiers.Any(SyntaxKind.AbstractKeyword))
                {
                    return;
                }
            }

            MethodSummary summary = MethodSummary.Factory.Summarize(method, machine, state);

            foreach (var givesUpNode in summary.GivesUpNodes)
            {
                MethodSummaryAnalysis.TryComputeGivesUpSetForSendControlFlowGraphNode(
                    givesUpNode, summary);
                MethodSummaryAnalysis.TryComputeGivesUpSetForCreateControlFlowGraphNode(
                    givesUpNode, summary);
                MethodSummaryAnalysis.TryComputeGivesUpSetForGenericControlFlowGraphNode(
                    givesUpNode, summary);
            }
        }
예제 #9
0
        /// <summary>
        /// Returns true if the given field symbol belongs to the machine
        /// that owns the given method summary. Returns false if not.
        /// </summary>
        /// <param name="symbol">Symbol</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean value</returns>
        internal bool DoesFieldBelongToMachine(ISymbol symbol, MethodSummary summary)
        {
            if (symbol == null || summary.Machine == null ||
                !(symbol is IFieldSymbol))
            {
                return(false);
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, this.Solution).Result;
            var fieldDecl  = definition.DeclaringSyntaxReferences.First().GetSyntax().
                             AncestorsAndSelf().OfType <FieldDeclarationSyntax>().First();

            if (summary.Machine.ChildNodes().OfType <FieldDeclarationSyntax>().Contains(fieldDecl))
            {
                return(true);
            }

            return(false);
        }
예제 #10
0
        /// <summary>
        /// Returns true if the given field symbol is being accessed
        /// before being reset.
        /// </summary>
        /// <param name="field">Field</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean value</returns>
        internal static bool IsAccessedBeforeBeingReset(ISymbol field, MethodSummary summary)
        {
            StateTransitionGraphNode stateTransitionNode = null;
            if (!AnalysisContext.StateTransitionGraphs.ContainsKey(summary.Machine))
            {
                return true;
            }

            stateTransitionNode = AnalysisContext.StateTransitionGraphs[summary.Machine].
                GetGraphNodeForSummary(summary);
            if (stateTransitionNode == null)
            {
                return true;
            }

            var result = stateTransitionNode.VisitSelfAndSuccessors(IsAccessedBeforeBeingReset,
                new Tuple<MethodSummary, ISymbol>(summary, field));

            return false;
        }
예제 #11
0
        /// <summary>
        /// Returns true if the field symbol is being accessed in a successor summary.
        /// </summary>
        protected bool IsFieldAccessedInSuccessor(IFieldSymbol fieldSymbol, MethodSummary summary,
                                                  StateMachine machine)
        {
            if (!this.Configuration.DoStateTransitionAnalysis)
            {
                return(true);
            }

            var successors = machine.GetSuccessorSummaries(summary);

            foreach (var successor in successors)
            {
                if (successor.SideEffectsInfo.FieldAccesses.ContainsKey(fieldSymbol))
                {
                    return(true);
                }
            }

            return(false);
        }
예제 #12
0
        /// <summary>
        /// Returns true if the given field symbol is being accessed
        /// before being reset.
        /// </summary>
        /// <param name="field">Field</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean value</returns>
        internal static bool IsAccessedBeforeBeingReset(ISymbol field, MethodSummary summary)
        {
            StateTransitionGraphNode stateTransitionNode = null;

            if (!AnalysisContext.StateTransitionGraphs.ContainsKey(summary.Machine))
            {
                return(true);
            }

            stateTransitionNode = AnalysisContext.StateTransitionGraphs[summary.Machine].
                                  GetGraphNodeForSummary(summary);
            if (stateTransitionNode == null)
            {
                return(true);
            }

            var result = stateTransitionNode.VisitSelfAndSuccessors(IsAccessedBeforeBeingReset,
                                                                    new Tuple <MethodSummary, ISymbol>(summary, field));

            return(false);
        }
예제 #13
0
        /// <summary>
        /// Returns the data flow map for the given control flow graph.
        /// </summary>
        /// <param name="summary">MethodSummary</param>
        /// <returns>DataFlowMap</returns>
        internal static DataFlowMap AnalyseControlFlowGraph(MethodSummary summary)
        {
            var dataFlowMap = new DataFlowMap();
            var model = AnalysisContext.Compilation.GetSemanticModel(summary.Method.SyntaxTree);

            foreach (var param in summary.Method.ParameterList.Parameters)
            {
                var declType = model.GetTypeInfo(param.Type).Type;
                if (Utilities.IsTypeAllowedToBeSend(declType) ||
                    Utilities.IsMachineType(declType, model))
                {
                    continue;
                }

                var paramSymbol = model.GetDeclaredSymbol(param);
                dataFlowMap.MapRefToSymbol(paramSymbol, paramSymbol, summary.Method.ParameterList,
                    summary.Node, false);
            }

            DataFlowAnalysis.AnalyseControlFlowGraphNode(summary.Node, summary.Node,
                summary.Method.ParameterList, model, dataFlowMap);

            return dataFlowMap;
        }
예제 #14
0
        /// <summary>
        /// Constructs the node using information from the given state transitions
        /// and action bindings.
        /// </summary>
        /// <param name="stateTransitions">State transitions</param>
        /// <param name="actionBindings">Action bindings</param>
        /// <param name="visited">Already visited nodes</param>
        private void Construct(Dictionary<ClassDeclarationSyntax, HashSet<ClassDeclarationSyntax>> stateTransitions,
            Dictionary<ClassDeclarationSyntax, HashSet<MethodDeclarationSyntax>> actionBindings,
            HashSet<StateTransitionGraphNode> visited)
        {
            visited.Add(this);

            foreach (var method in this.State.ChildNodes().OfType<MethodDeclarationSyntax>())
            {
                var summary = MethodSummary.Factory.Summarize(this.AnalysisContext, method);
                if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) &&
                    method.Identifier.ValueText.Equals("OnEntry"))
                {
                    this.OnEntry = summary;
                }
                else if (method.Modifiers.Any(SyntaxKind.OverrideKeyword) &&
                    method.Identifier.ValueText.Equals("OnExit"))
                {
                    this.OnExit = summary;
                }
            }

            var actions = new HashSet<MethodDeclarationSyntax>();
            if (actionBindings.ContainsKey(this.State))
            {
                actions = actionBindings[this.State];
            }

            foreach (var action in actions)
            {
                var actionSummary = MethodSummary.Factory.Summarize(this.AnalysisContext, action);
                this.Actions.Add(actionSummary);
            }

            var transitions = new HashSet<ClassDeclarationSyntax>();
            if (stateTransitions.ContainsKey(this.State))
            {
                transitions = stateTransitions[this.State];
            }

            foreach (var successorState in transitions)
            {
                var successor = visited.FirstOrDefault(v => v.State.Equals(successorState));
                if (successor != null)
                {
                    this.ISuccessors.Add(successor);
                    successor.IPredecessors.Add(this);
                }
                else
                {
                    successor = new StateTransitionGraphNode(this.AnalysisContext, successorState, this.Machine);
                    this.ISuccessors.Add(successor);
                    successor.IPredecessors.Add(this);
                    successor.Construct(stateTransitions, actionBindings, visited);
                }
            }
        }
예제 #15
0
 /// <summary>
 /// Analyzes the ownership of the given-up symbol in the candidate callee.
 /// </summary>
 protected abstract void AnalyzeOwnershipInCandidateCallee(GivenUpOwnershipSymbol givenUpSymbol, MethodSummary calleeSummary,
                                                           ExpressionSyntax call, Statement statement, StateMachine machine, SemanticModel model, TraceInfo trace);
예제 #16
0
        /// <summary>
        /// Computes the summary for the specified method.
        /// </summary>
        /// <param name="method">Method</param>
        private void SummarizeMethod(MethodDeclarationSyntax method)
        {
            var summary = MethodSummary.Create(this.AnalysisContext, method);

            this.MethodSummaries.Add(method, summary);
        }
예제 #17
0
        /// <summary>
        /// Tries to compute the 'gives_up' set of indexes for the given control flow graph node.
        /// If the node does not contain a generic 'gives_up' operation, then it returns false.
        /// </summary>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean value</returns>
        private static bool TryComputeGivesUpSetForGenericControlFlowGraphNode(ControlFlowGraphNode cfgNode,
                                                                               MethodSummary summary)
        {
            var callLocalDecl = cfgNode.SyntaxNodes.First() as LocalDeclarationStatementSyntax;
            var callExpr      = cfgNode.SyntaxNodes.First() as ExpressionStatementSyntax;

            InvocationExpressionSyntax call = null;

            if (callLocalDecl != null)
            {
                call = callLocalDecl.DescendantNodesAndSelf().OfType <InvocationExpressionSyntax>().First();
            }
            else if (callExpr != null)
            {
                call = callExpr.DescendantNodesAndSelf().OfType <InvocationExpressionSyntax>().First();
            }
            else if (call == null || !((call.Expression is MemberAccessExpressionSyntax) ||
                                       (call.Expression is IdentifierNameSyntax)))
            {
                return(false);
            }

            var model = AnalysisContext.Compilation.GetSemanticModel(call.SyntaxTree);

            if (call.Expression is MemberAccessExpressionSyntax)
            {
                var callStmt = call.Expression as MemberAccessExpressionSyntax;
                if (callStmt.Name.Identifier.ValueText.Equals("Send") ||
                    callStmt.Name.Identifier.ValueText.Equals("CreateMachine"))
                {
                    return(false);
                }
            }
            else if (call.Expression is IdentifierNameSyntax)
            {
                var callStmt = call.Expression as IdentifierNameSyntax;
                if (callStmt.Identifier.ValueText.Equals("Send") ||
                    callStmt.Identifier.ValueText.Equals("CreateMachine"))
                {
                    return(false);
                }
            }

            if (call.ArgumentList.Arguments.Count == 0)
            {
                return(false);
            }

            var callSymbol   = model.GetSymbolInfo(call).Symbol;
            var definition   = SymbolFinder.FindSourceDefinitionAsync(callSymbol, ProgramInfo.Solution).Result;
            var calleeMethod = definition.DeclaringSyntaxReferences.First().GetSyntax()
                               as BaseMethodDeclarationSyntax;
            var calleeSummary = MethodSummary.Factory.Summarize(calleeMethod);

            foreach (int idx in calleeSummary.GivesUpSet)
            {
                if (call.ArgumentList.Arguments[idx].Expression is ObjectCreationExpressionSyntax)
                {
                    var objCreation = call.ArgumentList.Arguments[idx].Expression
                                      as ObjectCreationExpressionSyntax;
                    foreach (var arg in objCreation.ArgumentList.Arguments)
                    {
                        MethodSummaryAnalysis.ComputeGivesUpSetForArgument(
                            arg.Expression, cfgNode, summary);
                    }
                }
                else if (call.ArgumentList.Arguments[idx].Expression is BinaryExpressionSyntax &&
                         call.ArgumentList.Arguments[idx].Expression.IsKind(SyntaxKind.AsExpression))
                {
                    var binExpr = call.ArgumentList.Arguments[idx].Expression
                                  as BinaryExpressionSyntax;
                    if ((binExpr.Left is IdentifierNameSyntax) || (binExpr.Left is MemberAccessExpressionSyntax))
                    {
                        MethodSummaryAnalysis.ComputeGivesUpSetForArgument(binExpr.Left,
                                                                           cfgNode, summary);
                    }
                    else if (binExpr.Left is InvocationExpressionSyntax)
                    {
                        var invocation = binExpr.Left as InvocationExpressionSyntax;
                        for (int i = 1; i < invocation.ArgumentList.Arguments.Count; i++)
                        {
                            MethodSummaryAnalysis.ComputeGivesUpSetForArgument(invocation.ArgumentList.
                                                                               Arguments[i].Expression, cfgNode, summary);
                        }
                    }
                }
                else if ((call.ArgumentList.Arguments[idx].Expression is IdentifierNameSyntax) ||
                         (call.ArgumentList.Arguments[idx].Expression is MemberAccessExpressionSyntax))
                {
                    MethodSummaryAnalysis.ComputeGivesUpSetForArgument(call.ArgumentList.
                                                                       Arguments[idx].Expression, cfgNode, summary);
                }
            }

            return(true);
        }
예제 #18
0
        /// <summary>
        /// Analyzes the ownership of the given-up symbol
        /// in the candidate callee.
        /// </summary>
        /// <param name="givenUpSymbol">GivenUpOwnershipSymbol</param>
        /// <param name="calleeSummary">MethodSummary</param>
        /// <param name="call">ExpressionSyntax</param>
        /// <param name="statement">Statement</param>
        /// <param name="machine">StateMachine</param>
        /// <param name="model">SemanticModel</param>
        /// <param name="trace">TraceInfo</param>
        protected override void AnalyzeOwnershipInCandidateCallee(GivenUpOwnershipSymbol givenUpSymbol,
                                                                  MethodSummary calleeSummary, ExpressionSyntax call, Statement statement,
                                                                  StateMachine machine, SemanticModel model, TraceInfo trace)
        {
            if (statement.Equals(givenUpSymbol.Statement) &&
                !statement.ControlFlowNode.IsSuccessorOf(
                    givenUpSymbol.Statement.ControlFlowNode))
            {
                return;
            }

            var invocation = call as InvocationExpressionSyntax;

            if (invocation != null)
            {
                this.AnalyzeOwnershipInExpression(givenUpSymbol, invocation.Expression, statement,
                                                  machine, model, trace);
            }

            ArgumentListSyntax argumentList = base.AnalysisContext.GetArgumentList(call);

            if (argumentList != null)
            {
                for (int idx = 0; idx < argumentList.Arguments.Count; idx++)
                {
                    var argType = model.GetTypeInfo(argumentList.Arguments[idx].Expression).Type;
                    if (base.AnalysisContext.IsTypePassedByValueOrImmutable(argType))
                    {
                        continue;
                    }

                    var argIdentifier = base.AnalysisContext.GetRootIdentifier(
                        argumentList.Arguments[idx].Expression);
                    ISymbol argSymbol = model.GetSymbolInfo(argIdentifier).Symbol;

                    if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(argSymbol,
                                                                           givenUpSymbol.ContainingSymbol, statement, givenUpSymbol.Statement))
                    {
                        if (calleeSummary.SideEffectsInfo.ParameterAccesses.ContainsKey(idx))
                        {
                            foreach (var access in calleeSummary.SideEffectsInfo.ParameterAccesses[idx])
                            {
                                TraceInfo newTrace = new TraceInfo();
                                newTrace.Merge(trace);
                                newTrace.AddErrorTrace(access.SyntaxNode);

                                AnalysisErrorReporter.ReportGivenUpOwnershipAccess(newTrace);
                            }
                        }

                        var fieldSymbols = calleeSummary.SideEffectsInfo.FieldFlowParamIndexes.Where(
                            v => v.Value.Contains(idx)).Select(v => v.Key);
                        foreach (var fieldSymbol in fieldSymbols)
                        {
                            if (base.IsFieldAccessedInSuccessor(fieldSymbol, statement.Summary, machine))
                            {
                                AnalysisErrorReporter.ReportGivenUpOwnershipFieldAssignment(trace, fieldSymbol);
                            }
                        }

                        if (calleeSummary.SideEffectsInfo.GivesUpOwnershipParamIndexes.Contains(idx))
                        {
                            AnalysisErrorReporter.ReportGivenUpOwnershipSending(trace, argSymbol);
                        }
                    }
                }
            }

            foreach (var fieldAccess in calleeSummary.SideEffectsInfo.FieldAccesses)
            {
                foreach (var access in fieldAccess.Value)
                {
                    if (statement.Summary.DataFlowAnalysis.FlowsIntoSymbol(givenUpSymbol.ContainingSymbol,
                                                                           fieldAccess.Key, givenUpSymbol.Statement, statement))
                    {
                        TraceInfo newTrace = new TraceInfo();
                        newTrace.Merge(trace);
                        newTrace.AddErrorTrace(access.SyntaxNode);

                        AnalysisErrorReporter.ReportGivenUpOwnershipFieldAccess(newTrace, fieldAccess.Key);
                    }
                }
            }
        }
예제 #19
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="summary">MethodSummary</param>
 internal ControlFlowGraphNode(MethodSummary summary)
 {
     this.Id = ControlFlowGraphNode.IdCounter++;
     this.Summary = summary;
     this.SyntaxNodes = new List<SyntaxNode>();
     this.IPredecessors = new HashSet<ControlFlowGraphNode>();
     this.ISuccessors = new HashSet<ControlFlowGraphNode>();
     this.IsGivesUpNode = false;
     this.IsJumpNode = false;
     this.IsLoopHeadNode = false;
 }
예제 #20
0
        /// <summary>
        /// Returns true if the given field symbol belongs to the machine
        /// that owns the given method summary. Returns false if not.
        /// </summary>
        /// <param name="symbol">Symbol</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean</returns>
        internal bool DoesFieldBelongToMachine(ISymbol symbol, MethodSummary summary)
        {
            if (symbol == null || summary.Machine == null ||
                !(symbol is IFieldSymbol))
            {
                return false;
            }

            var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, this.Solution).Result;
            var fieldDecl = definition.DeclaringSyntaxReferences.First().GetSyntax().
                AncestorsAndSelf().OfType<FieldDeclarationSyntax>().First();

            if (summary.Machine.ChildNodes().OfType<FieldDeclarationSyntax>().Contains(fieldDecl))
            {
                return true;
            }

            return false;
        }
예제 #21
0
        /// <summary>
        /// Tries to compute the 'gives_up' set of indexes for the given control flow graph node.
        /// If the node does not contain a 'Send' operation, then it returns false.
        /// </summary>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean value</returns>
        private bool TryComputeGivesUpSetForSendControlFlowGraphNode(ControlFlowGraphNode cfgNode,
            MethodSummary summary)
        {
            var sendExpr = cfgNode.SyntaxNodes.First() as ExpressionStatementSyntax;
            if (sendExpr == null)
            {
                return false;
            }

            var send = sendExpr.Expression as InvocationExpressionSyntax;
            if (send == null || !((send.Expression is MemberAccessExpressionSyntax) ||
                (send.Expression is IdentifierNameSyntax)))
            {
                return false;
            }

            if (((send.Expression is MemberAccessExpressionSyntax) &&
                !(send.Expression as MemberAccessExpressionSyntax).
                Name.Identifier.ValueText.Equals("Send")) ||
                ((send.Expression is IdentifierNameSyntax) &&
                !(send.Expression as IdentifierNameSyntax).
                Identifier.ValueText.Equals("Send")))
            {
                return false;
            }

            if (send.ArgumentList.Arguments[1].Expression is ObjectCreationExpressionSyntax)
            {
                var objCreation = send.ArgumentList.Arguments[1].Expression
                    as ObjectCreationExpressionSyntax;
                foreach (var arg in objCreation.ArgumentList.Arguments)
                {
                    this.ComputeGivesUpSetForArgument(arg.Expression, cfgNode, summary);
                }
            }
            else if (send.ArgumentList.Arguments[1].Expression is BinaryExpressionSyntax &&
                send.ArgumentList.Arguments[1].Expression.IsKind(SyntaxKind.AsExpression))
            {
                var binExpr = send.ArgumentList.Arguments[1].Expression
                    as BinaryExpressionSyntax;
                if ((binExpr.Left is IdentifierNameSyntax) || (binExpr.Left is MemberAccessExpressionSyntax))
                {
                    this.ComputeGivesUpSetForArgument(binExpr.Left, cfgNode, summary);
                }
                else if (binExpr.Left is InvocationExpressionSyntax)
                {
                    var invocation = binExpr.Left as InvocationExpressionSyntax;
                    for (int i = 1; i < invocation.ArgumentList.Arguments.Count; i++)
                    {
                        this.ComputeGivesUpSetForArgument(invocation.ArgumentList.
                            Arguments[i].Expression, cfgNode, summary);
                    }
                }
            }

            return true;
        }
예제 #22
0
        /// <summary>
        /// Tries to compute the 'gives_up' set of indexes for the given control flow graph node.
        /// If the node does not contain a generic 'gives_up' operation, then it returns false.
        /// </summary>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="summary">MethodSummary</param>
        /// <returns>Boolean value</returns>
        private bool TryComputeGivesUpSetForGenericControlFlowGraphNode(ControlFlowGraphNode cfgNode,
            MethodSummary summary)
        {
            var callLocalDecl = cfgNode.SyntaxNodes.First() as LocalDeclarationStatementSyntax;
            var callExpr = cfgNode.SyntaxNodes.First() as ExpressionStatementSyntax;

            InvocationExpressionSyntax call = null;
            if (callLocalDecl != null)
            {
                call = callLocalDecl.DescendantNodesAndSelf().OfType<InvocationExpressionSyntax>().First();
            }
            else if (callExpr != null)
            {
                call = callExpr.DescendantNodesAndSelf().OfType<InvocationExpressionSyntax>().First();
            }
            else if (call == null || !((call.Expression is MemberAccessExpressionSyntax) ||
                (call.Expression is IdentifierNameSyntax)))
            {
                return false;
            }

            var model = this.AnalysisContext.Compilation.GetSemanticModel(call.SyntaxTree);

            if (call.Expression is MemberAccessExpressionSyntax)
            {
                var callStmt = call.Expression as MemberAccessExpressionSyntax;
                if (callStmt.Name.Identifier.ValueText.Equals("Send") ||
                    callStmt.Name.Identifier.ValueText.Equals("CreateMachine"))
                {
                    return false;
                }
            }
            else if (call.Expression is IdentifierNameSyntax)
            {
                var callStmt = call.Expression as IdentifierNameSyntax;
                if (callStmt.Identifier.ValueText.Equals("Send") ||
                    callStmt.Identifier.ValueText.Equals("CreateMachine"))
                {
                    return false;
                }
            }

            if (call.ArgumentList.Arguments.Count == 0)
            {
                return false;
            }

            var callSymbol = model.GetSymbolInfo(call).Symbol;
            var definition = SymbolFinder.FindSourceDefinitionAsync(callSymbol,
                this.AnalysisContext.Solution).Result;
            var calleeMethod = definition.DeclaringSyntaxReferences.First().GetSyntax()
                as BaseMethodDeclarationSyntax;
            var calleeSummary = MethodSummary.Factory.Summarize(this.AnalysisContext, calleeMethod);

            foreach (int idx in calleeSummary.GivesUpSet)
            {
                if (call.ArgumentList.Arguments[idx].Expression is ObjectCreationExpressionSyntax)
                {
                    var objCreation = call.ArgumentList.Arguments[idx].Expression
                        as ObjectCreationExpressionSyntax;
                    foreach (var arg in objCreation.ArgumentList.Arguments)
                    {
                        this.ComputeGivesUpSetForArgument(arg.Expression, cfgNode, summary);
                    }
                }
                else if (call.ArgumentList.Arguments[idx].Expression is BinaryExpressionSyntax &&
                    call.ArgumentList.Arguments[idx].Expression.IsKind(SyntaxKind.AsExpression))
                {
                    var binExpr = call.ArgumentList.Arguments[idx].Expression
                        as BinaryExpressionSyntax;
                    if ((binExpr.Left is IdentifierNameSyntax) || (binExpr.Left is MemberAccessExpressionSyntax))
                    {
                        this.ComputeGivesUpSetForArgument(binExpr.Left, cfgNode, summary);
                    }
                    else if (binExpr.Left is InvocationExpressionSyntax)
                    {
                        var invocation = binExpr.Left as InvocationExpressionSyntax;
                        for (int i = 1; i < invocation.ArgumentList.Arguments.Count; i++)
                        {
                            this.ComputeGivesUpSetForArgument(invocation.ArgumentList.
                                Arguments[i].Expression, cfgNode, summary);
                        }
                    }
                }
                else if ((call.ArgumentList.Arguments[idx].Expression is IdentifierNameSyntax) ||
                    (call.ArgumentList.Arguments[idx].Expression is MemberAccessExpressionSyntax))
                {
                    this.ComputeGivesUpSetForArgument(call.ArgumentList.Arguments[idx].
                        Expression, cfgNode, summary);
                }
            }

            return true;
        }
예제 #23
0
        /// <summary>
        /// Computes the 'gives_up' set for the given argument.
        /// </summary>
        /// <param name="arg">Argument</param>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="summary">MethodSummary</param>
        private void ComputeGivesUpSetForArgument(ExpressionSyntax arg, ControlFlowGraphNode cfgNode,
            MethodSummary summary)
        {
            var model = this.AnalysisContext.Compilation.GetSemanticModel(arg.SyntaxTree);
            if (arg is IdentifierNameSyntax || arg is MemberAccessExpressionSyntax)
            {
                for (int idx = 0; idx < summary.Method.ParameterList.Parameters.Count; idx++)
                {
                    if (this.AnalysisContext.IsTypeAllowedToBeSend(summary.Method.ParameterList.
                        Parameters[idx].Type, model))
                    {
                        continue;
                    }

                    var paramSymbol = model.GetDeclaredSymbol(summary.Method.ParameterList.Parameters[idx]);
                    if (DataFlowAnalysis.FlowsFromTarget(arg, paramSymbol, summary.Node.SyntaxNodes.First(),
                        summary.Node, cfgNode.SyntaxNodes.First(), cfgNode, model, this.AnalysisContext))
                    {
                        summary.GivesUpSet.Add(idx);
                    }
                }
            }
            else if (arg is ObjectCreationExpressionSyntax)
            {
                var payload = arg as ObjectCreationExpressionSyntax;
                foreach (var item in payload.ArgumentList.Arguments)
                {
                    this.ComputeGivesUpSetForArgument(item.Expression, cfgNode, summary);
                }
            }
        }
예제 #24
0
        /// <summary>
        /// Resolves and returns all possible side effects at the point of the
        /// given call argument list.
        /// </summary>
        /// <param name="argumentList">Argument list</param>
        /// <param name="model">SemanticModel</param>
        /// <returns>Set of side effects</returns>
        internal Dictionary <ISymbol, HashSet <ISymbol> > GetResolvedSideEffects(ArgumentListSyntax argumentList,
                                                                                 SemanticModel model)
        {
            Dictionary <ISymbol, HashSet <ISymbol> > sideEffects = new Dictionary <ISymbol, HashSet <ISymbol> >();

            foreach (var sideEffect in this.SideEffects)
            {
                HashSet <ISymbol> argSymbols = new HashSet <ISymbol>();
                foreach (var index in sideEffect.Value)
                {
                    IdentifierNameSyntax arg = null;
                    var argExpr = argumentList.Arguments[index].Expression;
                    if (argExpr is IdentifierNameSyntax)
                    {
                        arg = argExpr as IdentifierNameSyntax;
                        var argType = model.GetTypeInfo(arg).Type;
                        if (this.AnalysisContext.IsTypeAllowedToBeSend(argType) ||
                            this.AnalysisContext.IsMachineType(argType, model))
                        {
                            continue;
                        }

                        argSymbols.Add(model.GetSymbolInfo(arg).Symbol);
                    }
                    else if (argExpr is MemberAccessExpressionSyntax)
                    {
                        var name    = (argExpr as MemberAccessExpressionSyntax).Name;
                        var argType = model.GetTypeInfo(name).Type;
                        if (this.AnalysisContext.IsTypeAllowedToBeSend(argType) ||
                            this.AnalysisContext.IsMachineType(argType, model))
                        {
                            continue;
                        }

                        arg = this.AnalysisContext.GetFirstNonMachineIdentifier(argExpr, model);
                        argSymbols.Add(model.GetSymbolInfo(arg).Symbol);
                    }
                    else if (argExpr is ObjectCreationExpressionSyntax)
                    {
                        var objCreation = argExpr as ObjectCreationExpressionSyntax;
                        var summary     = MethodSummary.TryGetSummary(objCreation, model, this.AnalysisContext);
                        if (summary == null)
                        {
                            continue;
                        }

                        var nestedSideEffects = summary.GetResolvedSideEffects(
                            objCreation.ArgumentList, model);
                        foreach (var nestedSideEffect in nestedSideEffects)
                        {
                            sideEffects.Add(nestedSideEffect.Key, nestedSideEffect.Value);
                        }
                    }
                    else if (argExpr is InvocationExpressionSyntax)
                    {
                        var invocation = argExpr as InvocationExpressionSyntax;
                        var summary    = MethodSummary.TryGetSummary(invocation, model, this.AnalysisContext);
                        if (summary == null)
                        {
                            continue;
                        }

                        var nestedSideEffects = summary.GetResolvedSideEffects(
                            invocation.ArgumentList, model);
                        foreach (var nestedSideEffect in nestedSideEffects)
                        {
                            sideEffects.Add(nestedSideEffect.Key, nestedSideEffect.Value);
                        }
                    }
                }

                sideEffects.Add(sideEffect.Key, argSymbols);
            }

            return(sideEffects);
        }
예제 #25
0
 /// <summary>
 /// Visits the state transition graph to find and return
 /// the node for the given summary.
 /// </summary>
 /// <param name="summary">MethodSummary</param>
 /// <returns>StateTransitionGraphNode</returns>
 internal StateTransitionGraphNode GetGraphNodeForSummary(MethodSummary summary)
 {
     return(this.GetGraphNodeForSummary(summary, new HashSet <StateTransitionGraphNode>()));
 }
예제 #26
0
        /// <summary>
        /// Resolves the side effects from the given invocation summary.
        /// </summary>
        /// <param name="call">Call</param>
        /// <param name="summary">MethodSummary</param>
        /// <param name="syntaxNode">SyntaxNode</param>
        /// <param name="cfgNode">ControlFlowGraphNode</param>
        /// <param name="model">SemanticModel</param>
        /// <param name="dataFlowMap">DataFlowMap</param>
        /// <returns>Set of reachable field symbols</returns>
        private static HashSet<ISymbol> ResolveSideEffectsInCall(InvocationExpressionSyntax call, MethodSummary summary,
            SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SemanticModel model, DataFlowMap dataFlowMap)
        {
            if (summary == null)
            {
                return new HashSet<ISymbol>();
            }

            HashSet<ISymbol> reachableFields = new HashSet<ISymbol>();
            var sideEffects = summary.GetResolvedSideEffects(call.ArgumentList, model);
            foreach (var sideEffect in sideEffects)
            {
                dataFlowMap.MapRefsToSymbol(sideEffect.Value, sideEffect.Key, syntaxNode, cfgNode);
                reachableFields.Add(sideEffect.Key);
            }

            foreach (var fieldAccess in summary.FieldAccessSet)
            {
                foreach (var access in fieldAccess.Value)
                {
                    if (cfgNode.Summary.FieldAccessSet.ContainsKey(fieldAccess.Key as IFieldSymbol))
                    {
                        cfgNode.Summary.FieldAccessSet[fieldAccess.Key as IFieldSymbol].Add(access);
                    }
                    else
                    {
                        cfgNode.Summary.FieldAccessSet.Add(fieldAccess.Key as IFieldSymbol, new HashSet<SyntaxNode>());
                        cfgNode.Summary.FieldAccessSet[fieldAccess.Key as IFieldSymbol].Add(access);
                    }
                }
            }

            return reachableFields;
        }
예제 #27
0
 /// <summary>
 /// Visits the state transition graph to find and return
 /// the node for the given summary.
 /// </summary>
 /// <param name="summary">MethodSummary</param>
 /// <returns>StateTransitionGraphNode</returns>
 internal StateTransitionGraphNode GetGraphNodeForSummary(MethodSummary summary)
 {
     return this.GetGraphNodeForSummary(summary, new HashSet<StateTransitionGraphNode>());
 }
예제 #28
0
        /// <summary>
        /// Returns the return symbols fromt he given object creation summary.
        /// </summary>
        /// <param name="call">Call</param>
        /// <param name="summary">MethodSummary</param>
        /// <param name="model">SemanticModel</param>
        /// <returns>Set of return symbols</returns>
        private static HashSet<ISymbol> GetReturnSymbols(ObjectCreationExpressionSyntax call, MethodSummary summary,
            SemanticModel model)
        {
            if (summary == null)
            {
                return new HashSet<ISymbol>();
            }

            return summary.GetResolvedReturnSymbols(call.ArgumentList, model);
        }
예제 #29
0
        /// <summary>
        /// Visits the state transition graph to find and return
        /// the node for the given summary.
        /// </summary>
        /// <param name="summary">MethodSummary</param>
        /// <param name="visited">Already visited nodes</param>
        /// <returns>StateTransitionGraphNode</returns>
        private StateTransitionGraphNode GetGraphNodeForSummary(MethodSummary summary,
            HashSet<StateTransitionGraphNode> visited)
        {
            visited.Add(this);

            StateTransitionGraphNode stateNode = null;
            if ((this.OnEntry != null && this.OnEntry.Equals(summary)) ||
                (this.OnExit != null && this.OnExit.Equals(summary)) ||
                this.Actions.Any(v => v.Equals(summary)))
            {
                stateNode = this;
            }
            else
            {
                foreach (var successor in this.ISuccessors.Where(v => !visited.Contains(v)))
                {
                    var node = successor.GetGraphNodeForSummary(summary, visited);
                    if (node != null)
                    {
                        stateNode = node;
                        break;
                    }
                }
            }

            return stateNode;
        }