/// <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); } } }
/// <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); } }
/// <summary> /// Analyses all the eligible methods of the given machine to compute each /// method summary. This process continues until it reaches a fix point. /// </summary> /// <param name="machine">Machine</param> private static void AnalyseMethodsInMachine(ClassDeclarationSyntax machine) { int fixPoint = 0; foreach (var nestedClass in machine.ChildNodes().OfType <ClassDeclarationSyntax>()) { foreach (var method in nestedClass.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (!Utilities.ShouldAnalyseMethod(method) || AnalysisContext.Summaries.ContainsKey(method)) { continue; } MethodSummaryAnalysis.ComputeSummaryForMethod(method, machine, nestedClass); if (!AnalysisContext.Summaries.ContainsKey(method)) { fixPoint++; } } } foreach (var method in machine.ChildNodes().OfType <MethodDeclarationSyntax>()) { if (!Utilities.ShouldAnalyseMethod(method) || AnalysisContext.Summaries.ContainsKey(method)) { continue; } MethodSummaryAnalysis.ComputeSummaryForMethod(method, machine, null); if (!AnalysisContext.Summaries.ContainsKey(method)) { fixPoint++; } } if (fixPoint > 0) { MethodSummaryAnalysis.AnalyseMethodsInMachine(machine); } }
/// <summary> /// Runs the analysis. /// </summary> public static void Run() { // Starts profiling the data flow analysis. if (Configuration.ShowDFARuntimeResults && !Configuration.ShowRuntimeResults && !Configuration.ShowROARuntimeResults) { Profiler.StartMeasuringExecutionTime(); } foreach (var machine in AnalysisContext.Machines) { MethodSummaryAnalysis.AnalyseMethodsInMachine(machine); } // Stops profiling the data flow analysis. if (Configuration.ShowDFARuntimeResults && !Configuration.ShowRuntimeResults && !Configuration.ShowROARuntimeResults) { Profiler.StopMeasuringExecutionTime(); } }
/// <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> /// 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); }