/// <summary> /// Returns true if the given expression flows in the target. /// </summary> /// <param name="variable">Variable</param> /// <param name="target">Target</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="model">SemanticModel</param> /// <returns>Boolean</returns> internal static bool FlowsIntoTarget(VariableDeclaratorSyntax variable, ISymbol target, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, SemanticModel model) { ISymbol reference = model.GetDeclaredSymbol(variable); return DataFlowAnalysis.FlowsIntoTarget(reference, target, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode); }
/// <summary> /// Returns true if the given expression flows in the target. /// </summary> /// <param name="expr">Expression</param> /// <param name="target">Target</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> internal static bool FlowsIntoTarget(ExpressionSyntax expr, ISymbol target, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, SemanticModel model, AnalysisContext context) { ISymbol reference = null; if (!context.TryGetSymbolFromExpression(out reference, expr, model)) { return false; } return DataFlowAnalysis.FlowsIntoTarget(reference, target, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode); }
/// <summary> /// Returns true if the given expression resets when flowing from the /// target in the given loop body control flow graph nodes. The given /// control flow graph nodes must be equal. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="model">SemanticModel</param> /// <returns>Boolean value</returns> internal static bool DoesResetInLoop(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, SemanticModel model) { ISymbol reference = null; if (!cfgNode.Equals(targetCfgNode) || !Utilities.TryGetSymbolFromExpression(out reference, expr, model)) { return false; } return DataFlowAnalysis.DoesResetInLoop(reference, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode); }
/// <summary> /// Handles the given using statement. /// </summary> /// <param name="stmt">Statement</param> /// <param name="successor">Successor</param> private void HandleUsingStatement(UsingStatementSyntax stmt, ControlFlowGraphNode successor) { this.SyntaxNodes.Add(stmt.Declaration); this.IsJumpNode = true; var usingNode = new ControlFlowGraphNode(this.Summary); this.ISuccessors.Add(usingNode); usingNode.IPredecessors.Add(this); if (stmt.Statement is BlockSyntax) { usingNode.Construct((stmt.Statement as BlockSyntax).Statements, 0, false, successor); } else { usingNode.Construct(new SyntaxList <StatementSyntax> { stmt.Statement }, 0, false, successor); } }
/// <summary> /// Handles the given switch statement. /// </summary> /// <param name="stmt">Statement</param> /// <param name="successor">Successor</param> private void HandleSwitchStatement(SwitchStatementSyntax stmt, ControlFlowGraphNode successor) { this.SyntaxNodes.Add(stmt.Expression); this.IsJumpNode = true; if (stmt.Sections.Count == 0 && successor != null) { this.ISuccessors.Add(successor); successor.IPredecessors.Add(this); return; } for (int idx = 0; idx < stmt.Sections.Count; idx++) { var statements = stmt.Sections[idx].Statements; bool containsBreak = false; foreach (var s in statements) { if (s is BreakStatementSyntax) { containsBreak = true; break; } } var switchNode = new ControlFlowGraphNode(this.Summary); this.ISuccessors.Add(switchNode); switchNode.IPredecessors.Add(this); if (containsBreak || idx == stmt.Sections.Count - 1) { switchNode.Construct(statements, 0, false, successor); } else { switchNode.Construct(statements, 0, false, null); } } }
/// <summary> /// Tries to capture a potential field acccess in the given expression. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void TryCaptureFieldAccess(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!(expr is MemberAccessExpressionSyntax)) { return; } var name = (expr as MemberAccessExpressionSyntax).Name; var identifier = context.GetFirstNonMachineIdentifier(expr, model); if (identifier == null || name == null) { return; } var type = model.GetTypeInfo(identifier).Type; if (context.IsTypeAllowedToBeSend(type) || context.IsMachineType(type, model) || name.Equals(identifier)) { return; } var symbol = model.GetSymbolInfo(identifier).Symbol; var definition = SymbolFinder.FindSourceDefinitionAsync(symbol, context.Solution).Result; if (!(definition is IFieldSymbol)) { return; } var fieldDecl = definition.DeclaringSyntaxReferences.First().GetSyntax(). AncestorsAndSelf().OfType<FieldDeclarationSyntax>().First(); if (dataFlowMap.DoesSymbolReset(symbol, cfgNode.Summary.Node.SyntaxNodes.First(), cfgNode.Summary.Node, syntaxNode, cfgNode, true)) { return; } if (cfgNode.Summary.FieldAccessSet.ContainsKey(symbol as IFieldSymbol)) { cfgNode.Summary.FieldAccessSet[symbol as IFieldSymbol].Add(syntaxNode); } else { cfgNode.Summary.FieldAccessSet.Add(symbol as IFieldSymbol, new HashSet<SyntaxNode>()); cfgNode.Summary.FieldAccessSet[symbol as IFieldSymbol].Add(syntaxNode); } }
/// <summary> /// Resolves the object type of the given symbol on the given syntax node. /// </summary> /// <param name="types">Set of object type symbols</param> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <returns>Boolean</returns> private static bool ResolveObjectType(out HashSet<ITypeSymbol> types, ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap) { types = new HashSet<ITypeSymbol>(); Dictionary<ISymbol, HashSet<ITypeSymbol>> objectTypeMap = null; if (!dataFlowMap.TryGetObjectTypeMapForSyntaxNode(syntaxNode, cfgNode, out objectTypeMap)) { return false; } if (!objectTypeMap.ContainsKey(symbol)) { return false; } types = objectTypeMap[symbol]; return true; }
/// <summary> /// Checks if the gives up call has a field symbol argument that is not /// already mapped and, if yes, maps it. /// </summary> /// <param name="call">Call</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void CheckForNonMappedFieldSymbol(InvocationExpressionSyntax call, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!cfgNode.IsGivesUpNode) { return; } List<MemberAccessExpressionSyntax> accesses; if (cfgNode.Summary.GivesUpSet.Count == 0 && call.Expression.DescendantNodesAndSelf(). OfType<IdentifierNameSyntax>().Last().ToString().Equals("Send")) { accesses = call.ArgumentList.Arguments[1].DescendantNodesAndSelf(). OfType<MemberAccessExpressionSyntax>().ToList(); } else { accesses = call.ArgumentList.DescendantNodesAndSelf().OfType<MemberAccessExpressionSyntax>().ToList(); } foreach (var access in accesses) { IdentifierNameSyntax id = context.GetFirstNonMachineIdentifier(access, model); if (id == null) { continue; } var accessSymbol = model.GetSymbolInfo(id).Symbol; dataFlowMap.MapSymbolIfNotExists(accessSymbol, cfgNode.SyntaxNodes[0], cfgNode); } }
/// <summary> /// Marks that the symbol has been reassigned a reference. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> private void MarkSymbolReassignment(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (!this.ResetMap.ContainsKey(cfgNode)) { this.ResetMap.Add(cfgNode, new Dictionary<SyntaxNode, HashSet<ISymbol>>()); this.ResetMap[cfgNode].Add(syntaxNode, new HashSet<ISymbol>()); } else if (!this.ResetMap[cfgNode].ContainsKey(syntaxNode)) { this.ResetMap[cfgNode].Add(syntaxNode, new HashSet<ISymbol>()); } this.ResetMap[cfgNode][syntaxNode].Add(symbol); }
/// <summary> /// Transfers the data flow map from the previous node to the new node. /// </summary> /// <param name="previousSyntaxNode">Previous syntaxNode</param> /// <param name="previousCfgNode">Previous cfgNode</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> internal void Transfer(SyntaxNode previousSyntaxNode, ControlFlowGraphNode previousCfgNode, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (!this.Map.ContainsKey(cfgNode)) { this.Map.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ISymbol>>>()); this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } else if (!this.Map[cfgNode].ContainsKey(syntaxNode)) { this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } Dictionary<ISymbol, HashSet<ISymbol>> previousMap = null; if (this.TryGetMapForSyntaxNode(previousSyntaxNode, previousCfgNode, out previousMap)) { foreach (var pair in previousMap) { if (!this.Map[cfgNode][syntaxNode].ContainsKey(pair.Key)) { this.Map[cfgNode][syntaxNode].Add(pair.Key, new HashSet<ISymbol>()); } foreach (var reference in pair.Value) { this.Map[cfgNode][syntaxNode][pair.Key].Add(reference); } } } if (!this.ReachabilityMap.ContainsKey(cfgNode)) { this.ReachabilityMap.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ISymbol>>>()); this.ReachabilityMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } else if (!this.ReachabilityMap[cfgNode].ContainsKey(syntaxNode)) { this.ReachabilityMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } Dictionary<ISymbol, HashSet<ISymbol>> previousReachabilityMap = null; if (this.TryGetReachabilityMapForSyntaxNode(previousSyntaxNode, previousCfgNode, out previousReachabilityMap)) { foreach (var pair in previousReachabilityMap) { if (!this.ReachabilityMap[cfgNode][syntaxNode].ContainsKey(pair.Key)) { this.ReachabilityMap[cfgNode][syntaxNode].Add(pair.Key, new HashSet<ISymbol>()); } foreach (var reference in pair.Value) { this.ReachabilityMap[cfgNode][syntaxNode][pair.Key].Add(reference); } } } if (!this.ObjectTypeMap.ContainsKey(cfgNode)) { this.ObjectTypeMap.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ITypeSymbol>>>()); this.ObjectTypeMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ITypeSymbol>>()); } else if (!this.ObjectTypeMap[cfgNode].ContainsKey(syntaxNode)) { this.ObjectTypeMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ITypeSymbol>>()); } Dictionary<ISymbol, HashSet<ITypeSymbol>> previousObjectTypeMap = null; if (this.TryGetObjectTypeMapForSyntaxNode(previousSyntaxNode, previousCfgNode, out previousObjectTypeMap)) { foreach (var pair in previousObjectTypeMap) { if (!this.ObjectTypeMap[cfgNode][syntaxNode].ContainsKey(pair.Key)) { this.ObjectTypeMap[cfgNode][syntaxNode].Add(pair.Key, new HashSet<ITypeSymbol>()); } foreach (var type in pair.Value) { this.ObjectTypeMap[cfgNode][syntaxNode][pair.Key].Add(type); } } } }
/// <summary> /// Checks if the data flow analysis reached a fixpoint regarding the given successor. /// </summary> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="successorCfgNode">Successor controlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <returns>Boolean</returns> private static bool ReachedFixpoint(SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, ControlFlowGraphNode successorCfgNode, DataFlowMap dataFlowMap) { Dictionary<ISymbol, HashSet<ISymbol>> currentMap = null; if (!dataFlowMap.TryGetMapForSyntaxNode(syntaxNode, cfgNode, out currentMap)) { return false; } Dictionary<ISymbol, HashSet<ISymbol>> successorMap = null; if (!dataFlowMap.TryGetMapForSyntaxNode(successorCfgNode.SyntaxNodes.First(), successorCfgNode, out successorMap)) { return false; } foreach (var pair in currentMap) { if (!successorMap.ContainsKey(pair.Key) || !successorMap[pair.Key].SetEquals(pair.Value)) { return false; } } return true; }
/// <summary> /// Tries to get the list of potential methods that can override the given virtual call. /// If it cannot find such methods then it returns false. /// </summary> /// <param name="overriders">List of overrider methods</param> /// <param name="virtualCall">Virtual call</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="originalMachine">Original machine</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> internal static bool TryGetPotentialMethodOverriders(out HashSet<MethodDeclarationSyntax> overriders, InvocationExpressionSyntax virtualCall, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, ClassDeclarationSyntax originalMachine, SemanticModel model, AnalysisContext context) { overriders = new HashSet<MethodDeclarationSyntax>(); ISymbol calleeSymbol = null; SimpleNameSyntax callee = null; bool isThis = false; if (virtualCall.Expression is MemberAccessExpressionSyntax) { var expr = virtualCall.Expression as MemberAccessExpressionSyntax; var identifier = expr.Expression.DescendantNodesAndSelf(). OfType<IdentifierNameSyntax>().Last(); calleeSymbol = model.GetSymbolInfo(identifier).Symbol; if (expr.Expression is ThisExpressionSyntax || context.IsMachineType(identifier, model)) { callee = expr.Name; isThis = true; } } else { callee = virtualCall.Expression as IdentifierNameSyntax; isThis = true; } if (isThis) { foreach (var nestedClass in originalMachine.ChildNodes().OfType<ClassDeclarationSyntax>()) { foreach (var method in nestedClass.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return true; } } } foreach (var method in originalMachine.ChildNodes().OfType<MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return true; } } return false; } if (calleeSymbol == null) { return false; } Dictionary<ISymbol, HashSet<ITypeSymbol>> objectTypeMap = null; if (!cfgNode.Summary.DataFlowMap.TryGetObjectTypeMapForSyntaxNode( syntaxNode, cfgNode, out objectTypeMap)) { return false; } if (!objectTypeMap.ContainsKey(calleeSymbol)) { return false; } foreach (var objectType in objectTypeMap[calleeSymbol]) { MethodDeclarationSyntax m = null; if (InheritanceAnalysis.TryGetMethodFromType(out m, objectType, virtualCall, context)) { overriders.Add(m); } } return true; }
/// <summary> /// Returns true if the node is a predecessor of the given node. /// Returns false if not. /// </summary> /// <param name="node">ControlFlowGraphNode</param> /// <returns>Boolean value</returns> internal bool IsPredecessorOf(ControlFlowGraphNode node) { return(this.IsPredecessorOf(node, new HashSet <ControlFlowGraphNode>())); }
/// <summary> /// Constructs the node from the given list of statements starting /// at the given index. /// </summary> /// <param name="stmtList">List of statements</param> /// <param name="index">Index</param> /// <param name="isBound">Processes only one statement</param> /// <param name="successor">Successor</param> internal void Construct(SyntaxList <StatementSyntax> stmtList, int index, bool isBound, ControlFlowGraphNode successor) { int boundary = stmtList.Count; if (isBound && index == stmtList.Count) { boundary = stmtList.Count; } else if (isBound) { boundary = index + 1; } for (int idx = index; idx < boundary; idx++) { ControlFlowGraphNode givesUpNode = null; ControlFlowGraphNode jumpNode = null; ControlFlowGraphNode succNode = null; if (stmtList[idx] is ExpressionStatementSyntax || stmtList[idx] is LocalDeclarationStatementSyntax) { var invocations = stmtList[idx].DescendantNodesAndSelf(). OfType <InvocationExpressionSyntax>(); if (invocations.Count() > 0) { var call = invocations.First(); if (this.IsGivesUpOperation(call)) { if (this.SyntaxNodes.Count == 0) { givesUpNode = this; } else { givesUpNode = new ControlFlowGraphNode(this.Summary); this.ISuccessors.Add(givesUpNode); givesUpNode.IPredecessors.Add(this); } givesUpNode.IsGivesUpNode = true; this.Summary.GivesUpNodes.Add(givesUpNode); givesUpNode.SyntaxNodes.Add(stmtList[idx]); if (idx < boundary - 1 && stmtList[idx + 1] is BreakStatementSyntax) { if (successor != null && successor.LoopExitNode != null) { givesUpNode.ISuccessors.Add(successor.LoopExitNode); successor.LoopExitNode.IPredecessors.Add(givesUpNode); } } else if (idx < boundary - 1 && stmtList[idx + 1] is ContinueStatementSyntax) { if (successor != null) { givesUpNode.ISuccessors.Add(successor); successor.IPredecessors.Add(givesUpNode); } } else if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); givesUpNode.ISuccessors.Add(succNode); succNode.IPredecessors.Add(givesUpNode); succNode.Construct(stmtList, idx + 1, false, successor); } else if (successor != null) { givesUpNode.ISuccessors.Add(successor); successor.IPredecessors.Add(givesUpNode); } return; } } this.SyntaxNodes.Add(stmtList[idx]); continue; } else if (stmtList[idx] is BreakStatementSyntax) { if (successor != null && successor.LoopExitNode != null) { this.ISuccessors.Add(successor.LoopExitNode); successor.LoopExitNode.IPredecessors.Add(this); } return; } else if (stmtList[idx] is ContinueStatementSyntax) { if (successor != null) { this.ISuccessors.Add(successor); successor.IPredecessors.Add(this); } return; } else if (stmtList[idx] is ReturnStatementSyntax) { this.SyntaxNodes.Add(stmtList[idx]); continue; } if (this.SyntaxNodes.Count == 0) { jumpNode = this; } else { jumpNode = new ControlFlowGraphNode(this.Summary); this.ISuccessors.Add(jumpNode); jumpNode.IPredecessors.Add(this); } if (stmtList[idx] is IfStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleIfStatement(stmtList[idx] as IfStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleIfStatement(stmtList[idx] as IfStatementSyntax, successor); } } else if (stmtList[idx] is ForStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleForStatement(stmtList[idx] as ForStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleForStatement(stmtList[idx] as ForStatementSyntax, successor); } } else if (stmtList[idx] is WhileStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleWhileStatement(stmtList[idx] as WhileStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleWhileStatement(stmtList[idx] as WhileStatementSyntax, successor); } } else if (stmtList[idx] is DoStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleDoStatement(stmtList[idx] as DoStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleDoStatement(stmtList[idx] as DoStatementSyntax, successor); } } else if (stmtList[idx] is ForEachStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleForeachStatement(stmtList[idx] as ForEachStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleForeachStatement(stmtList[idx] as ForEachStatementSyntax, successor); } } else if (stmtList[idx] is SwitchStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleSwitchStatement(stmtList[idx] as SwitchStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleSwitchStatement(stmtList[idx] as SwitchStatementSyntax, successor); } } else if (stmtList[idx] is TryStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleTryStatement(stmtList[idx] as TryStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleTryStatement(stmtList[idx] as TryStatementSyntax, successor); } } else if (stmtList[idx] is UsingStatementSyntax) { if (idx < boundary - 1) { succNode = new ControlFlowGraphNode(this.Summary); jumpNode.HandleUsingStatement(stmtList[idx] as UsingStatementSyntax, succNode); succNode.Construct(stmtList, idx + 1, false, successor); return; } else { jumpNode.HandleUsingStatement(stmtList[idx] as UsingStatementSyntax, successor); } } } if (successor != null && (this.IsJumpNode || (!this.IsJumpNode && this.ISuccessors.Count == 0))) { this.ISuccessors.Add(successor); successor.IPredecessors.Add(this); } if (this.SyntaxNodes.Count == 0) { foreach (var pred in this.IPredecessors) { pred.ISuccessors.Remove(this); } } }
/// <summary> /// Returns true if the given symbol resets in successor /// control flow graph nodes. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="target">Target</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="visited">Already visited cfgNodes</param> /// <returns>Boolean</returns> private static bool DoesResetInSuccessors(ISymbol symbol, ISymbol target, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, ControlFlowGraphNode targetCfgNode, HashSet<ControlFlowGraphNode> visited, bool track = false) { visited.Add(targetCfgNode); foreach (var node in targetCfgNode.SyntaxNodes) { if (track) { if (targetCfgNode.Summary.DataFlowMap.DoesSymbolReset(symbol, syntaxNode, cfgNode, node, targetCfgNode) && !DataFlowAnalysis.FlowsIntoTarget(symbol, target, syntaxNode, cfgNode, node, targetCfgNode)) { return true; } } if (node.Equals(syntaxNode)) { track = true; } } if (targetCfgNode.ISuccessors.Count == 0) { return false; } List<bool> results = new List<bool>(); foreach (var successor in targetCfgNode.ISuccessors.Where(v => !visited.Contains(v))) { results.Add(DataFlowAnalysis.DoesResetInSuccessors(symbol, target, syntaxNode, cfgNode, successor, visited, true)); } if (results.Contains(true)) { return true; } else { return false; } }
/// <summary> /// Returns true if the given symbol resets in successor /// control flow graph nodes. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="target">Target</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <returns>Boolean</returns> internal static bool DoesResetInSuccessors(ISymbol symbol, ISymbol target, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { return DataFlowAnalysis.DoesResetInSuccessors(symbol, target, syntaxNode, cfgNode, cfgNode, new HashSet<ControlFlowGraphNode>()); }
/// <summary> /// Maps the given set of references to the given symbol. /// </summary> /// <param name="references">Set of references</param> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> /// <param name="markReset">Should mark symbol as reset</param> internal void MapRefsToSymbol(HashSet <ISymbol> references, ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, bool markReset = true) { if (!this.Map.ContainsKey(cfgNode)) { this.Map.Add(cfgNode, new Dictionary <SyntaxNode, Dictionary <ISymbol, HashSet <ISymbol> > >()); this.Map[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ISymbol> >()); } else if (!this.Map[cfgNode].ContainsKey(syntaxNode)) { this.Map[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ISymbol> >()); } HashSet <ISymbol> additionalRefs = new HashSet <ISymbol>(); foreach (var reference in references) { if (this.Map[cfgNode][syntaxNode].ContainsKey(reference)) { foreach (var r in this.Map[cfgNode][syntaxNode][reference]) { if (!reference.Equals(r)) { additionalRefs.Add(r); } } } } if (this.Map[cfgNode][syntaxNode].ContainsKey(symbol) && additionalRefs.Count > 0) { this.Map[cfgNode][syntaxNode][symbol].Clear(); } else if (additionalRefs.Count > 0) { this.Map[cfgNode][syntaxNode].Add(symbol, new HashSet <ISymbol>()); } else if (this.Map[cfgNode][syntaxNode].ContainsKey(symbol)) { this.Map[cfgNode][syntaxNode][symbol].Clear(); foreach (var reference in references) { this.Map[cfgNode][syntaxNode][symbol].Add(reference); } } else { this.Map[cfgNode][syntaxNode].Add(symbol, new HashSet <ISymbol>()); foreach (var reference in references) { this.Map[cfgNode][syntaxNode][symbol].Add(reference); } } foreach (var r in additionalRefs) { this.Map[cfgNode][syntaxNode][symbol].Add(r); } if (markReset) { this.MarkSymbolReassignment(symbol, syntaxNode, cfgNode); } }
/// <summary> /// Erases the set of object types from the given symbol. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> internal void EraseObjectTypesFromSymbol(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (this.ObjectTypeMap.ContainsKey(cfgNode) && this.ObjectTypeMap[cfgNode].ContainsKey(syntaxNode) && this.ObjectTypeMap[cfgNode][syntaxNode].ContainsKey(symbol)) { this.ObjectTypeMap[cfgNode][syntaxNode].Remove(symbol); } }
/// <summary> /// Returns true if the given symbol resets until it reaches the /// target control flow graph node. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="track">Tracking</param> /// <returns>Boolean value</returns> internal bool DoesSymbolReset(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, bool track = false) { return(this.DoesSymbolReset(symbol, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode, new HashSet <ControlFlowGraphNode>(), track)); }
/// <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); }
/// <summary> /// Transfers the data flow map from the previous node to the new node. /// </summary> /// <param name="previousSyntaxNode">Previous syntaxNode</param> /// <param name="previousCfgNode">Previous cfgNode</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> internal void Transfer(SyntaxNode previousSyntaxNode, ControlFlowGraphNode previousCfgNode, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (!this.Map.ContainsKey(cfgNode)) { this.Map.Add(cfgNode, new Dictionary <SyntaxNode, Dictionary <ISymbol, HashSet <ISymbol> > >()); this.Map[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ISymbol> >()); } else if (!this.Map[cfgNode].ContainsKey(syntaxNode)) { this.Map[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ISymbol> >()); } Dictionary <ISymbol, HashSet <ISymbol> > previousMap = null; if (this.TryGetMapForSyntaxNode(previousSyntaxNode, previousCfgNode, out previousMap)) { foreach (var pair in previousMap) { if (!this.Map[cfgNode][syntaxNode].ContainsKey(pair.Key)) { this.Map[cfgNode][syntaxNode].Add(pair.Key, new HashSet <ISymbol>()); } foreach (var reference in pair.Value) { this.Map[cfgNode][syntaxNode][pair.Key].Add(reference); } } } if (!this.ReachabilityMap.ContainsKey(cfgNode)) { this.ReachabilityMap.Add(cfgNode, new Dictionary <SyntaxNode, Dictionary <ISymbol, HashSet <ISymbol> > >()); this.ReachabilityMap[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ISymbol> >()); } else if (!this.ReachabilityMap[cfgNode].ContainsKey(syntaxNode)) { this.ReachabilityMap[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ISymbol> >()); } Dictionary <ISymbol, HashSet <ISymbol> > previousReachabilityMap = null; if (this.TryGetReachabilityMapForSyntaxNode(previousSyntaxNode, previousCfgNode, out previousReachabilityMap)) { foreach (var pair in previousReachabilityMap) { if (!this.ReachabilityMap[cfgNode][syntaxNode].ContainsKey(pair.Key)) { this.ReachabilityMap[cfgNode][syntaxNode].Add(pair.Key, new HashSet <ISymbol>()); } foreach (var reference in pair.Value) { this.ReachabilityMap[cfgNode][syntaxNode][pair.Key].Add(reference); } } } if (!this.ObjectTypeMap.ContainsKey(cfgNode)) { this.ObjectTypeMap.Add(cfgNode, new Dictionary <SyntaxNode, Dictionary <ISymbol, HashSet <ITypeSymbol> > >()); this.ObjectTypeMap[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ITypeSymbol> >()); } else if (!this.ObjectTypeMap[cfgNode].ContainsKey(syntaxNode)) { this.ObjectTypeMap[cfgNode].Add(syntaxNode, new Dictionary <ISymbol, HashSet <ITypeSymbol> >()); } Dictionary <ISymbol, HashSet <ITypeSymbol> > previousObjectTypeMap = null; if (this.TryGetObjectTypeMapForSyntaxNode(previousSyntaxNode, previousCfgNode, out previousObjectTypeMap)) { foreach (var pair in previousObjectTypeMap) { if (!this.ObjectTypeMap[cfgNode][syntaxNode].ContainsKey(pair.Key)) { this.ObjectTypeMap[cfgNode][syntaxNode].Add(pair.Key, new HashSet <ITypeSymbol>()); } foreach (var type in pair.Value) { this.ObjectTypeMap[cfgNode][syntaxNode][pair.Key].Add(type); } } } }
/// <summary> /// Tries to return the reachability map for the given syntax node. Returns false /// and a null map, if it cannot find such map. /// </summary> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="map">Map</param> /// <returns>Boolean value</returns> internal bool TryGetReachabilityMapForSyntaxNode(SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, out Dictionary<ISymbol, HashSet<ISymbol>> map) { if (cfgNode == null || syntaxNode == null) { map = null; return false; } if (this.ReachabilityMap.ContainsKey(cfgNode)) { if (this.ReachabilityMap[cfgNode].ContainsKey(syntaxNode)) { map = this.ReachabilityMap[cfgNode][syntaxNode]; return true; } else { map = null; return false; } } else { map = null; return false; } }
/// <summary> /// Returns true if the given symbol resets until it reaches the /// target control flow graph node. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="visited">Already visited cfgNodes</param> /// <param name="track">Tracking</param> /// <returns>Boolean value</returns> internal bool DoesSymbolReset(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, HashSet<ControlFlowGraphNode> visited, bool track) { visited.Add(cfgNode); bool result = false; if (syntaxNode.Equals(targetSyntaxNode) && cfgNode.Equals(targetCfgNode) && !track) { return result; } foreach (var node in cfgNode.SyntaxNodes) { if (track && this.ResetMap.ContainsKey(cfgNode) && this.ResetMap[cfgNode].ContainsKey(node) && this.ResetMap[cfgNode][node].Contains(symbol)) { result = true; break; } if (!track && node.Equals(syntaxNode)) { track = true; } } if (!result) { foreach (var successor in cfgNode.ISuccessors.Where(v => !visited.Contains(v))) { if ((successor.Equals(targetCfgNode) || successor.IsPredecessorOf(targetCfgNode)) && this.DoesSymbolReset(symbol, successor.SyntaxNodes.First(), successor, targetSyntaxNode, targetCfgNode, visited, true)) { result = true; break; } } } return result; }
/// <summary> /// Returns true if the given symbol resets until it reaches the /// target control flow graph node. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <param name="track">Tracking</param> /// <returns>Boolean value</returns> internal bool DoesSymbolReset(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode, bool track = false) { return this.DoesSymbolReset(symbol, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode, new HashSet<ControlFlowGraphNode>(), track); }
/// <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; }
/// <summary> /// Returns true if there is a map for the given syntax node. /// </summary> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <returns>Boolean value</returns> internal bool ExistsMapForSyntaxNode(SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (this.Map.ContainsKey(cfgNode)) { if (this.Map[cfgNode].ContainsKey(syntaxNode)) { return true; } else { return false; } } else { return false; } }
/// <summary> /// Tries to capture a potential parameter acccess in the given expression. /// </summary> /// <param name="expr">Expression</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> private static void TryCaptureParameterAccess(ExpressionSyntax expr, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!(expr is MemberAccessExpressionSyntax)) { return; } var name = (expr as MemberAccessExpressionSyntax).Name; var identifier = context.GetFirstNonMachineIdentifier(expr, model); if (identifier == null || name == null) { return; } var type = model.GetTypeInfo(identifier).Type; if (context.IsTypeAllowedToBeSend(type) || context.IsMachineType(type, model) || name.Equals(identifier)) { return; } var symbol = model.GetSymbolInfo(identifier).Symbol; if (symbol == null) { return; } Dictionary<ISymbol, HashSet<ISymbol>> map = null; if (!dataFlowMap.TryGetMapForSyntaxNode(syntaxNode, cfgNode, out map)) { return; } Dictionary<ISymbol, int> indexMap = new Dictionary<ISymbol, int>(); var parameterList = cfgNode.Summary.Method.ParameterList.Parameters; for (int idx = 0; idx < parameterList.Count; idx++) { var paramSymbol = model.GetDeclaredSymbol(parameterList[idx]); indexMap.Add(paramSymbol, idx); } if (map.ContainsKey(symbol)) { foreach (var reference in map[symbol]) { if (reference.Kind == SymbolKind.Parameter) { if (reference.Equals(symbol) && dataFlowMap.DoesSymbolReset( reference, cfgNode.Summary.Node.SyntaxNodes.First(), cfgNode.Summary.Node, syntaxNode, cfgNode, true)) { continue; } int index = indexMap[reference]; if (cfgNode.Summary.AccessSet.ContainsKey(index)) { cfgNode.Summary.AccessSet[index].Add(syntaxNode); } else { cfgNode.Summary.AccessSet.Add(index, new HashSet<SyntaxNode>()); cfgNode.Summary.AccessSet[index].Add(syntaxNode); } } } } }
/// <summary> /// Maps the given set of object types to the given symbol. /// </summary> /// <param name="types">Set of object types</param> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> internal void MapObjectTypesToSymbol(HashSet<ITypeSymbol> types, ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (!this.ObjectTypeMap.ContainsKey(cfgNode)) { this.ObjectTypeMap.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ITypeSymbol>>>()); this.ObjectTypeMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ITypeSymbol>>()); } else if (!this.ObjectTypeMap[cfgNode].ContainsKey(syntaxNode)) { this.ObjectTypeMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ITypeSymbol>>()); } if (this.ObjectTypeMap[cfgNode][syntaxNode].ContainsKey(symbol)) { this.ObjectTypeMap[cfgNode][syntaxNode][symbol].Clear(); foreach (var type in types) { this.ObjectTypeMap[cfgNode][syntaxNode][symbol].Add(type); } } else { this.ObjectTypeMap[cfgNode][syntaxNode].Add(symbol, new HashSet<ITypeSymbol>()); foreach (var type in types) { this.ObjectTypeMap[cfgNode][syntaxNode][symbol].Add(type); } } }
/// <summary> /// Tries to capture potential return symbols. /// </summary> /// <param name="returnSymbols">Set of return symbols</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="model">SemanticModel</param> /// <param name="dataFlowMap">DataFlowMap</param> private static void TryCaptureReturnSymbols(HashSet<ISymbol> returnSymbols, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SemanticModel model, DataFlowMap dataFlowMap) { Dictionary<ISymbol, HashSet<ISymbol>> map = null; if (returnSymbols == null || !dataFlowMap.TryGetMapForSyntaxNode(syntaxNode, cfgNode, out map)) { return; } Dictionary<ISymbol, int> indexMap = new Dictionary<ISymbol, int>(); var parameterList = cfgNode.Summary.Method.ParameterList.Parameters; for (int idx = 0; idx < parameterList.Count; idx++) { var paramSymbol = model.GetDeclaredSymbol(parameterList[idx]); indexMap.Add(paramSymbol, idx); } foreach (var symbol in returnSymbols) { if (symbol.Kind == SymbolKind.Parameter) { if (dataFlowMap.DoesSymbolReset(symbol, cfgNode.Summary.Node.SyntaxNodes. First(), cfgNode.Summary.Node, syntaxNode, cfgNode, true)) { continue; } cfgNode.Summary.ReturnSet.Item1.Add(indexMap[symbol]); } else if (symbol.Kind == SymbolKind.Field) { cfgNode.Summary.ReturnSet.Item2.Add(symbol as IFieldSymbol); } else if (map.ContainsKey(symbol)) { foreach (var reference in map[symbol].Where(v => v.Kind == SymbolKind.Field)) { cfgNode.Summary.ReturnSet.Item2.Add(reference as IFieldSymbol); } } } }
/// <summary> /// Maps the given set of reachable field symbols to the given symbol. /// </summary> /// <param name="fields">Set of field symbols</param> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> internal void MapReachableFieldsToSymbol(HashSet<ISymbol> fields, ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (!this.ReachabilityMap.ContainsKey(cfgNode)) { this.ReachabilityMap.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ISymbol>>>()); this.ReachabilityMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } else if (!this.ReachabilityMap[cfgNode].ContainsKey(syntaxNode)) { this.ReachabilityMap[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } if (this.ReachabilityMap[cfgNode][syntaxNode].ContainsKey(symbol)) { this.ReachabilityMap[cfgNode][syntaxNode][symbol].Clear(); foreach (var reference in fields) { this.ReachabilityMap[cfgNode][syntaxNode][symbol].Add(reference); } } else { this.ReachabilityMap[cfgNode][syntaxNode].Add(symbol, new HashSet<ISymbol>()); foreach (var reference in fields) { this.ReachabilityMap[cfgNode][syntaxNode][symbol].Add(reference); } } }
/// <summary> /// Returns true if the given symbol resets when flowing from the /// target in the given loop body control flow graph nodes. The /// given control flow graph nodes must be equal. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <returns>Boolean</returns> internal static bool DoesResetInLoop(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode) { if (cfgNode.ISuccessors.Count == 0) { return false; } var successor = cfgNode.ISuccessors.First(); while (!successor.IsLoopHeadNode) { if (!successor.IsLoopHeadNode && successor.ISuccessors.Count == 0) { return false; } else { successor = successor.ISuccessors.First(); } } var backwards = cfgNode.Summary.DataFlowMap.DoesSymbolReset(symbol, syntaxNode, cfgNode, successor.SyntaxNodes.First(), successor); var forwards = cfgNode.Summary.DataFlowMap.DoesSymbolReset(symbol, successor.SyntaxNodes.First(), successor, syntaxNode, cfgNode); return backwards || forwards; }
/// <summary> /// Maps the given reference to the given symbol. /// </summary> /// <param name="reference">Reference</param> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> /// <param name="markReset">Should mark symbol as reset</param> internal void MapRefToSymbol(ISymbol reference, ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, bool markReset = true) { if (!this.Map.ContainsKey(cfgNode)) { this.Map.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ISymbol>>>()); this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } else if (!this.Map[cfgNode].ContainsKey(syntaxNode)) { this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } HashSet<ISymbol> additionalRefs = new HashSet<ISymbol>(); if (this.Map[cfgNode][syntaxNode].ContainsKey(reference)) { foreach (var r in this.Map[cfgNode][syntaxNode][reference]) { if (!reference.Equals(r)) { additionalRefs.Add(r); } } } if (this.Map[cfgNode][syntaxNode].ContainsKey(symbol) && additionalRefs.Count > 0) { this.Map[cfgNode][syntaxNode][symbol] = new HashSet<ISymbol>(); } else if (additionalRefs.Count > 0) { this.Map[cfgNode][syntaxNode].Add(symbol, new HashSet<ISymbol>()); } else if (this.Map[cfgNode][syntaxNode].ContainsKey(symbol)) { this.Map[cfgNode][syntaxNode][symbol] = new HashSet<ISymbol> { reference }; } else { this.Map[cfgNode][syntaxNode].Add(symbol, new HashSet<ISymbol> { reference }); } foreach (var r in additionalRefs) { this.Map[cfgNode][syntaxNode][symbol].Add(r); } if (markReset) { this.MarkSymbolReassignment(symbol, syntaxNode, cfgNode); } }
/// <summary> /// Returns all possible aliases of the given symbol. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <returns>Set of aliases</returns> internal static HashSet<ISymbol> GetAliases(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { HashSet<ISymbol> aliases = new HashSet<ISymbol>(); Dictionary<ISymbol, HashSet<ISymbol>> dataFlowMap = null; if (!cfgNode.Summary.DataFlowMap.TryGetMapForSyntaxNode(syntaxNode, cfgNode, out dataFlowMap) || !dataFlowMap.ContainsKey(symbol)) { return aliases; } foreach (var reference in dataFlowMap[symbol].Where(v => !v.Equals(symbol))) { aliases.Add(reference); } return aliases; }
/// <summary> /// Maps the given symbol if its not already mapped. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> internal void MapSymbolIfNotExists(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (!this.Map.ContainsKey(cfgNode)) { this.Map.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ISymbol>>>()); this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } else if (!this.Map[cfgNode].ContainsKey(syntaxNode)) { this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } if (!this.Map[cfgNode][syntaxNode].ContainsKey(symbol)) { this.Map[cfgNode][syntaxNode][symbol] = new HashSet<ISymbol> { symbol }; } }
/// <summary> /// Performs data flow analysis on the given control flow graph node. /// </summary> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="previousCfgNode">Previous controlFlowGraphNode</param> /// <param name="previousSyntaxNode">Previous syntaxNode</param> /// <param name="dataFlowMap">DataFlowMap</param> /// <param name="model">SemanticModel</param> /// <param name="context">AnalysisContext</param> /// <returns>Boolean</returns> private static void AnalyseControlFlowGraphNode(ControlFlowGraphNode cfgNode, ControlFlowGraphNode previousCfgNode, SyntaxNode previousSyntaxNode, DataFlowMap dataFlowMap, SemanticModel model, AnalysisContext context) { if (!cfgNode.IsJumpNode && !cfgNode.IsLoopHeadNode) { foreach (var syntaxNode in cfgNode.SyntaxNodes) { dataFlowMap.Transfer(previousSyntaxNode, previousCfgNode, syntaxNode, cfgNode); var stmt = syntaxNode as StatementSyntax; var localDecl = stmt.DescendantNodesAndSelf().OfType<LocalDeclarationStatementSyntax>().FirstOrDefault(); var expr = stmt.DescendantNodesAndSelf().OfType<ExpressionStatementSyntax>().FirstOrDefault(); var ret = stmt.DescendantNodesAndSelf().OfType<ReturnStatementSyntax>().FirstOrDefault(); if (localDecl != null) { var varDecl = (stmt as LocalDeclarationStatementSyntax).Declaration; foreach (var variable in varDecl.Variables) { if (variable.Initializer == null) { continue; } DataFlowAnalysis.TryCaptureParameterAccess(variable.Initializer.Value, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(variable.Initializer.Value, syntaxNode, cfgNode, dataFlowMap, model, context); ITypeSymbol declType = null; if (variable.Initializer.Value is LiteralExpressionSyntax && variable.Initializer.Value.IsKind(SyntaxKind.NullLiteralExpression)) { declType = model.GetTypeInfo(varDecl.Type).Type; } else { declType = model.GetTypeInfo(variable.Initializer.Value).Type; } if (context.IsTypeAllowedToBeSend(declType) || context.IsMachineType(declType, model)) { continue; } var declSymbol = model.GetDeclaredSymbol(variable); if (variable.Initializer.Value is IdentifierNameSyntax || variable.Initializer.Value is MemberAccessExpressionSyntax) { ISymbol varSymbol = null; if (variable.Initializer.Value is IdentifierNameSyntax) { varSymbol = model.GetSymbolInfo(variable.Initializer.Value as IdentifierNameSyntax).Symbol; } else if (variable.Initializer.Value is MemberAccessExpressionSyntax) { varSymbol = model.GetSymbolInfo((variable.Initializer.Value as MemberAccessExpressionSyntax).Name).Symbol; } dataFlowMap.MapRefToSymbol(varSymbol, declSymbol, syntaxNode, cfgNode); HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, varSymbol, syntaxNode, cfgNode, dataFlowMap)) { dataFlowMap.MapObjectTypesToSymbol(objectTypes, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } else if (variable.Initializer.Value is LiteralExpressionSyntax && variable.Initializer.Value.IsKind(SyntaxKind.NullLiteralExpression)) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (variable.Initializer.Value is InvocationExpressionSyntax) { var invocation = variable.Initializer.Value as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (returnSymbols.Contains(declSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode, false); } else { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode); } if (reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, declSymbol, syntaxNode, cfgNode); } if (summary != null && summary.ReturnTypeSet.Count > 0) { dataFlowMap.MapObjectTypesToSymbol(summary.ReturnTypeSet, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } else if (variable.Initializer.Value is ObjectCreationExpressionSyntax) { var objCreation = variable.Initializer.Value as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(declSymbol, syntaxNode, cfgNode); } else if (returnSymbols.Contains(declSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode, false); } else { dataFlowMap.MapRefsToSymbol(returnSymbols, declSymbol, syntaxNode, cfgNode); } if (reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, declSymbol, syntaxNode, cfgNode); } var typeSymbol = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (typeSymbol != null) { dataFlowMap.MapObjectTypesToSymbol(new HashSet<ITypeSymbol> { typeSymbol }, declSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(declSymbol, syntaxNode, cfgNode); } } } } else if (expr != null) { if (expr.Expression is BinaryExpressionSyntax) { var binaryExpr = expr.Expression as BinaryExpressionSyntax; DataFlowAnalysis.TryCaptureParameterAccess(binaryExpr.Left, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureParameterAccess(binaryExpr.Right, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(binaryExpr.Left, syntaxNode, cfgNode, dataFlowMap, model, context); DataFlowAnalysis.TryCaptureFieldAccess(binaryExpr.Right, syntaxNode, cfgNode, dataFlowMap, model, context); IdentifierNameSyntax lhs = null; ISymbol lhsFieldSymbol = null; if (binaryExpr.Left is IdentifierNameSyntax) { lhs = binaryExpr.Left as IdentifierNameSyntax; var lhsType = model.GetTypeInfo(lhs).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } } else if (binaryExpr.Left is MemberAccessExpressionSyntax) { var name = (binaryExpr.Left as MemberAccessExpressionSyntax).Name; var lhsType = model.GetTypeInfo(name).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } lhs = context.GetFirstNonMachineIdentifier(binaryExpr.Left, model); lhsFieldSymbol = model.GetSymbolInfo(name as IdentifierNameSyntax).Symbol; } else if (binaryExpr.Left is ElementAccessExpressionSyntax) { var memberAccess = (binaryExpr.Left as ElementAccessExpressionSyntax); if (memberAccess.Expression is IdentifierNameSyntax) { lhs = memberAccess.Expression as IdentifierNameSyntax; var lhsType = model.GetTypeInfo(lhs).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } } else if (memberAccess.Expression is MemberAccessExpressionSyntax) { var name = (memberAccess.Expression as MemberAccessExpressionSyntax).Name; var lhsType = model.GetTypeInfo(name).Type; if (context.IsTypeAllowedToBeSend(lhsType) || context.IsMachineType(lhsType, model)) { previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; continue; } lhs = context.GetFirstNonMachineIdentifier(memberAccess.Expression, model); lhsFieldSymbol = model.GetSymbolInfo(name as IdentifierNameSyntax).Symbol; } } var leftSymbol = model.GetSymbolInfo(lhs).Symbol; if (binaryExpr.Right is IdentifierNameSyntax || binaryExpr.Right is MemberAccessExpressionSyntax) { IdentifierNameSyntax rhs = null; if (binaryExpr.Right is IdentifierNameSyntax) { rhs = binaryExpr.Right as IdentifierNameSyntax; } else if (binaryExpr.Right is MemberAccessExpressionSyntax) { rhs = context.GetFirstNonMachineIdentifier(binaryExpr.Right, model); } var rightSymbol = model.GetSymbolInfo(rhs).Symbol; dataFlowMap.MapRefToSymbol(rightSymbol, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefToSymbol(rightSymbol, lhsFieldSymbol, syntaxNode, cfgNode); } HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, rightSymbol, syntaxNode, cfgNode, dataFlowMap)) { dataFlowMap.MapObjectTypesToSymbol(objectTypes, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is LiteralExpressionSyntax && binaryExpr.Right.IsKind(SyntaxKind.NullLiteralExpression)) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is InvocationExpressionSyntax) { var invocation = binaryExpr.Right as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); DataFlowAnalysis.CheckForNonMappedFieldSymbol(invocation, cfgNode, dataFlowMap, model, context); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (returnSymbols.Contains(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode, false); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode, false); } } else { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } } if (lhsFieldSymbol != null && reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } if (summary != null && summary.ReturnTypeSet.Count > 0) { dataFlowMap.MapObjectTypesToSymbol(summary.ReturnTypeSet, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } else if (binaryExpr.Right is ObjectCreationExpressionSyntax) { var objCreation = binaryExpr.Right as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); var reachableSymbols = DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); var returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); if (returnSymbols.Count == 0) { dataFlowMap.ResetSymbol(leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.ResetSymbol(lhsFieldSymbol, syntaxNode, cfgNode); } } else if (returnSymbols.Contains(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode, false); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode, false); } } else { dataFlowMap.MapRefsToSymbol(returnSymbols, leftSymbol, syntaxNode, cfgNode); if (lhsFieldSymbol != null && !lhsFieldSymbol.Equals(leftSymbol)) { dataFlowMap.MapRefsToSymbol(returnSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } } if (lhsFieldSymbol != null && reachableSymbols.Count > 0) { dataFlowMap.MapReachableFieldsToSymbol(reachableSymbols, lhsFieldSymbol, syntaxNode, cfgNode); } var typeSymbol = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (typeSymbol != null) { dataFlowMap.MapObjectTypesToSymbol(new HashSet<ITypeSymbol> { typeSymbol }, leftSymbol, syntaxNode, cfgNode); } else { dataFlowMap.EraseObjectTypesFromSymbol(leftSymbol, syntaxNode, cfgNode); } } } else if (expr.Expression is InvocationExpressionSyntax) { var invocation = expr.Expression as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); DataFlowAnalysis.CheckForNonMappedFieldSymbol(invocation, cfgNode, dataFlowMap, model, context); } } else if (ret != null) { HashSet<ISymbol> returnSymbols = null; if (ret.Expression is IdentifierNameSyntax || ret.Expression is MemberAccessExpressionSyntax) { IdentifierNameSyntax rhs = null; if (ret.Expression is IdentifierNameSyntax) { rhs = ret.Expression as IdentifierNameSyntax; } else if (ret.Expression is MemberAccessExpressionSyntax) { rhs = context.GetFirstNonMachineIdentifier(ret.Expression, model); } var rightSymbol = model.GetSymbolInfo(rhs).Symbol; returnSymbols = new HashSet<ISymbol> { rightSymbol }; HashSet<ITypeSymbol> objectTypes = null; if (DataFlowAnalysis.ResolveObjectType(out objectTypes, rightSymbol, syntaxNode, cfgNode, dataFlowMap)) { foreach (var objectType in objectTypes) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } } else if (ret.Expression is InvocationExpressionSyntax) { var invocation = ret.Expression as InvocationExpressionSyntax; var summary = MethodSummary.TryGetSummary(invocation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(invocation, summary, syntaxNode, cfgNode, model, dataFlowMap); returnSymbols = DataFlowAnalysis.GetReturnSymbols(invocation, summary, model); if (summary != null) { foreach (var objectType in summary.ReturnTypeSet) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } } else if (ret.Expression is ObjectCreationExpressionSyntax) { var objCreation = ret.Expression as ObjectCreationExpressionSyntax; var summary = MethodSummary.TryGetSummary(objCreation, model, context); DataFlowAnalysis.ResolveSideEffectsInCall(objCreation, summary, syntaxNode, cfgNode, model, dataFlowMap); returnSymbols = DataFlowAnalysis.GetReturnSymbols(objCreation, summary, model); var objectType = model.GetSymbolInfo(objCreation.Type).Symbol as ITypeSymbol; if (objectType != null) { cfgNode.Summary.ReturnTypeSet.Add(objectType); } } DataFlowAnalysis.TryCaptureReturnSymbols(returnSymbols, syntaxNode, cfgNode, model, dataFlowMap); } previousSyntaxNode = syntaxNode; previousCfgNode = cfgNode; } } else { dataFlowMap.Transfer(previousSyntaxNode, previousCfgNode, cfgNode.SyntaxNodes[0], cfgNode); previousSyntaxNode = cfgNode.SyntaxNodes[0]; previousCfgNode = cfgNode; } foreach (var successor in cfgNode.ISuccessors) { if (DataFlowAnalysis.ReachedFixpoint(previousSyntaxNode, cfgNode, successor, dataFlowMap)) { continue; } DataFlowAnalysis.AnalyseControlFlowGraphNode(successor, cfgNode, previousSyntaxNode, dataFlowMap, model, context); } }
/// <summary> /// Prints the data flow map of the given syntax node. /// </summary> internal void Print(ControlFlowGraphNode cfgNode) { Output.Print("\nPrinting data flow map of cfgNode {0}: ", cfgNode.Id); if (this.Map.ContainsKey(cfgNode)) { foreach (var syntaxNode in this.Map[cfgNode]) { Output.Print(" > syntaxNode: " + syntaxNode.Key); foreach (var pair in syntaxNode.Value) { foreach (var symbol in pair.Value) { Output.Print(" " + pair.Key.Name + " ::= " + symbol.Name); } } } } }
/// <summary> /// Returns true if the given symbol flows into the target symbol. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="target">Target</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="targetSyntaxNode">Target syntaxNode</param> /// <param name="targetCfgNode">Target controlFlowGraphNode</param> /// <returns>Boolean</returns> internal static bool FlowsIntoTarget(ISymbol symbol, ISymbol target, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, SyntaxNode targetSyntaxNode, ControlFlowGraphNode targetCfgNode) { Dictionary<ISymbol, HashSet<ISymbol>> dataFlowMap = null; if (!targetCfgNode.Summary.DataFlowMap.TryGetMapForSyntaxNode(targetSyntaxNode, targetCfgNode, out dataFlowMap) || !dataFlowMap.ContainsKey(symbol)) { return false; } if (symbol.Equals(target) && cfgNode.Summary.DataFlowMap.DoesSymbolReset( symbol, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode)) { return false; } Dictionary<ISymbol, HashSet<ISymbol>> reachabilityMap = null; if (targetCfgNode.Summary.DataFlowMap.TryGetReachabilityMapForSyntaxNode(targetSyntaxNode, targetCfgNode, out reachabilityMap) && reachabilityMap.ContainsKey(symbol)) { foreach (var field in reachabilityMap[symbol]) { foreach (var reference in dataFlowMap[field]) { dataFlowMap[symbol].Add(reference); } } } foreach (var reference in dataFlowMap[symbol]) { if (reference.Equals(target)) { return true; } } if (dataFlowMap.ContainsKey(target)) { foreach (var reference in dataFlowMap[target]) { if (!cfgNode.Summary.DataFlowMap.DoesSymbolReset(symbol, syntaxNode, cfgNode, targetSyntaxNode, targetCfgNode)) { if (reference.Equals(symbol)) { return true; } foreach (var symbolRef in dataFlowMap[symbol]) { if (reference.Equals(symbolRef)) { return true; } } } } } return false; }
/// <summary> /// Resets the references of the given symbol. /// </summary> /// <param name="symbol">Symbol</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">CfgNode</param> internal void ResetSymbol(ISymbol symbol, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode) { if (!this.Map.ContainsKey(cfgNode)) { this.Map.Add(cfgNode, new Dictionary<SyntaxNode, Dictionary<ISymbol, HashSet<ISymbol>>>()); this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } else if (!this.Map[cfgNode].ContainsKey(syntaxNode)) { this.Map[cfgNode].Add(syntaxNode, new Dictionary<ISymbol, HashSet<ISymbol>>()); } if (this.Map[cfgNode][syntaxNode].ContainsKey(symbol)) { this.Map[cfgNode][syntaxNode][symbol] = new HashSet<ISymbol> { symbol }; } else { this.Map[cfgNode][syntaxNode].Add(symbol, new HashSet<ISymbol> { symbol }); } this.MarkSymbolReassignment(symbol, syntaxNode, cfgNode); }
/// <summary> /// Tries to get the list of potential methods that can override the given virtual call. /// If it cannot find such methods then it returns false. /// </summary> /// <param name="overriders">List of overrider methods</param> /// <param name="virtualCall">Virtual call</param> /// <param name="syntaxNode">SyntaxNode</param> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="originalMachine">Original machine</param> /// <param name="model">SemanticModel</param> /// <returns>Boolean value</returns> internal static bool TryGetPotentialMethodOverriders(out HashSet <MethodDeclarationSyntax> overriders, InvocationExpressionSyntax virtualCall, SyntaxNode syntaxNode, ControlFlowGraphNode cfgNode, ClassDeclarationSyntax originalMachine, SemanticModel model) { overriders = new HashSet <MethodDeclarationSyntax>(); ISymbol calleeSymbol = null; SimpleNameSyntax callee = null; bool isThis = false; if (virtualCall.Expression is MemberAccessExpressionSyntax) { var expr = virtualCall.Expression as MemberAccessExpressionSyntax; var identifier = expr.Expression.DescendantNodesAndSelf(). OfType <IdentifierNameSyntax>().Last(); calleeSymbol = model.GetSymbolInfo(identifier).Symbol; if (expr.Expression is ThisExpressionSyntax || Utilities.IsMachineType(identifier, model)) { callee = expr.Name; isThis = true; } } else { callee = virtualCall.Expression as IdentifierNameSyntax; isThis = true; } if (isThis) { foreach (var nestedClass in originalMachine.ChildNodes().OfType <ClassDeclarationSyntax>()) { foreach (var method in nestedClass.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return(true); } } } foreach (var method in originalMachine.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (method.Identifier.ToString().Equals(callee.Identifier.ToString())) { overriders.Add(method); return(true); } } return(false); } if (calleeSymbol == null) { return(false); } Dictionary <ISymbol, HashSet <ITypeSymbol> > objectTypeMap = null; if (!cfgNode.Summary.DataFlowMap.TryGetObjectTypeMapForSyntaxNode( syntaxNode, cfgNode, out objectTypeMap)) { return(false); } if (!objectTypeMap.ContainsKey(calleeSymbol)) { return(false); } foreach (var objectType in objectTypeMap[calleeSymbol]) { MethodDeclarationSyntax m = null; if (InheritanceAnalysis.TryGetMethodFromType(out m, objectType, virtualCall)) { overriders.Add(m); } } return(true); }
/// <summary> /// Tries to compute the 'gives_up' set of indexes for the given control flow graph node. /// If the node does not contain a 'Create' operation, then it returns false. /// </summary> /// <param name="cfgNode">ControlFlowGraphNode</param> /// <param name="summary">MethodSummary</param> /// <returns>Boolean value</returns> private static bool TryComputeGivesUpSetForCreateControlFlowGraphNode(ControlFlowGraphNode cfgNode, MethodSummary summary) { var createExpr = cfgNode.SyntaxNodes.First() as ExpressionStatementSyntax; if (createExpr == null) { return(false); } var create = createExpr.Expression as InvocationExpressionSyntax; if (create == null || !((create.Expression is MemberAccessExpressionSyntax) || (create.Expression is IdentifierNameSyntax))) { return(false); } if (((create.Expression is MemberAccessExpressionSyntax) && !(create.Expression as MemberAccessExpressionSyntax). Name.Identifier.ValueText.Equals("CreateMachine")) || ((create.Expression is IdentifierNameSyntax) && !(create.Expression as IdentifierNameSyntax). Identifier.ValueText.Equals("CreateMachine"))) { return(false); } if (create.ArgumentList.Arguments.Count == 0) { return(true); } if (create.ArgumentList.Arguments[0].Expression is ObjectCreationExpressionSyntax) { var objCreation = create.ArgumentList.Arguments[0].Expression as ObjectCreationExpressionSyntax; foreach (var arg in objCreation.ArgumentList.Arguments) { MethodSummaryAnalysis.ComputeGivesUpSetForArgument(arg.Expression, cfgNode, summary); } } else if (create.ArgumentList.Arguments[0].Expression is BinaryExpressionSyntax && create.ArgumentList.Arguments[0].Expression.IsKind(SyntaxKind.AsExpression)) { var binExpr = create.ArgumentList.Arguments[0].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 ((create.ArgumentList.Arguments[0].Expression is IdentifierNameSyntax) || (create.ArgumentList.Arguments[0].Expression is MemberAccessExpressionSyntax)) { MethodSummaryAnalysis.ComputeGivesUpSetForArgument(create.ArgumentList. Arguments[0].Expression, cfgNode, summary); } return(true); }