/// This does the interprocedural analysis. /// It (currently) does NOT support recursive method invocations /// </summary> /// <param name="instruction"></param> /// <param name="resolvedCallee"></param> /// <param name="calleeCFG"></param> private InterProceduralReturnInfo InterproceduralAnalysis(InterProceduralCallInfo callInfo, ControlFlowGraph calleeCFG) { if (stackDepth > InterproceduralManager.MaxStackDepth) { callInfo.CallerState.Dependencies.IsTop = true; AnalysisStats.AddAnalysisReason(new AnalysisReason(callInfo.Caller, callInfo.Instruction, String.Format(CultureInfo.InvariantCulture, "Reach maximum call depth {0}", callInfo.Callee.Name))); return(new InterProceduralReturnInfo(callInfo.CallerState)); } stackDepth++; // I currently do not support recursive calls // Will add support for this in the near future if (callStack.Contains(callInfo.Callee)) { callInfo.CallerState.Dependencies.IsTop = true; AnalysisStats.AddAnalysisReason(new AnalysisReason(callInfo.Caller, callInfo.Instruction, String.Format(CultureInfo.InvariantCulture, "Recursive call to {0}", callInfo.Callee.Name))); return(new InterProceduralReturnInfo(callInfo.CallerState)); } this.callStack.Push(callInfo.Callee); //Console.WriteLine("Analyzing Method {0} Stack: {1}", new string(' ',stackDepth*2) + callInfo.Callee.ToString(), stackDepth); // 1) Bind PTG and create a Poinst-to Analysis for the callee. In pta.Result[node.Exit] is the PTG at exit of the callee var calleePTG = PTABindCallerCallee(callInfo.CallerPTG, callInfo.CallArguments, callInfo.Callee); SimplePointsToAnalysis calleePTA = new SimplePointsToAnalysis(calleeCFG, callInfo.Callee, calleePTG); IDictionary <IVariable, IExpression> equalities = new Dictionary <IVariable, IExpression>(); calleeCFG.PropagateExpressions(equalities); // 2) Bind Parameters of the dependency analysis VariableRangeDomain boundVariablesRanges; var calleeDomain = BindCallerCallee(callInfo, out boundVariablesRanges); var rangesAnalysis = new RangeAnalysis(calleeCFG, callInfo.Callee, boundVariablesRanges); // 4) Now we perform the analyses rangesAnalysis.Analyze(); calleeDomain.PTG = calleePTG; var dependencyAnalysis = new IteratorDependencyAnalysis(processToAnalyze, callInfo.Callee, calleeCFG, calleePTA, callInfo.ProtectedNodes, equalities, this, rangesAnalysis, calleeDomain, callInfo.ScopeData); // If we already did the dataflow analysis for this method we recover the dataflow state // This should be adapted (or removed) if we want the analysis to be context sensitive //if (dataflowCache.ContainsKey(callInfo.Callee)) //{ // var previosResult = dataflowCache[callInfo.Callee]; // //DataFlowAnalysisResult<DependencyPTGDomain>[] resultsCopy = new DataFlowAnalysisResult<DependencyPTGDomain>[previosResult.Length]; // //for(int i=0; i< previosResult.Length; i++) // //{ // // resultsCopy[i] = new DataFlowAnalysisResult<DependencyPTGDomain>(); // // resultsCopy[i].Input = previosResult[i].Input!=null? previosResult[i].Input.Clone(): null; // // resultsCopy[i].Output = previosResult[i].Output!=null? previosResult[i].Output.Clone(): null; // //} // //dependencyAnalysis.SetPreviousResult(resultsCopy); // dependencyAnalysis.SetPreviousResult(previosResult); //} dependencyAnalysis.Analyze(); this.dataflowCache[callInfo.Callee] = dependencyAnalysis.Result; stackDepth--; this.callStack.Pop(); // 3) Bind callee with caller // Should I need the PTG of caller and callee? //var exitCalleePTG = calleePTA.Result[calleeCFG.Exit.Id].Output; var exitCalleePTG = dependencyAnalysis.Result[calleeCFG.Exit.Id].Output.PTG; var exitResult = BindCalleeCaller(callInfo, calleeCFG, dependencyAnalysis, rangesAnalysis); // Recover the frame of the original Ptg and bind ptg results //PointsToGraph bindPtg = PTABindCaleeCalleer(callInfo.CallLHS, calleeCFG, calleePTA); var bindPtg = PTABindCaleeCalleer(callInfo.CallLHS, calleeCFG, exitCalleePTG, calleePTA.ReturnVariable); exitResult.PTG = bindPtg; return(new InterProceduralReturnInfo(exitResult) { InputColumns = dependencyAnalysis.InputColumns, OutputColumns = dependencyAnalysis.OutputColumns }); //return new InterProceduralReturnInfo(exitResult, bindPtg); }
public static SarifLog AnalyzeDll(string inputPath, ScopeMethodKind kind, bool useScopeFactory = true, bool interProc = false, StreamWriter outputStream = null) { // Determine whether to use Interproc analysis AnalysisOptions.DoInterProcAnalysis = interProc; AnalysisStats.TotalNumberFolders++; var host = new MyHost(); PlatformTypes.Resolve(host); var loader = new MyLoader(host); host.Loader = loader; var scopeGenAssembly = loader.LoadMainAssembly(inputPath); AnalysisStats.TotalDllsFound++; loader.LoadCoreAssembly(); var program = new ScopeProgramAnalysis(host, loader); // program.interprocAnalysisManager = new InterproceduralManager(host); program.ScopeGenAssembly = scopeGenAssembly; //program.ReferenceFiles = referenceFiles; program.ClassFilters = new HashSet <string>(); program.ClousureFilters = new HashSet <string>(); program.EntryMethods = new HashSet <string>(); if (kind == ScopeMethodKind.Reducer || kind == ScopeMethodKind.All) { program.ClassFilters.Add("Reducer"); program.ClousureFilters.Add("<Reduce>d__"); program.EntryMethods.Add("Reduce"); } if (kind == ScopeMethodKind.Producer || kind == ScopeMethodKind.All) { program.ClassFilters.Add("Processor"); program.ClousureFilters.Add("<Process>d__"); program.EntryMethods.Add("Process"); //program.ClassFilter = "Producer"; //program.ClousureFilter = "<Produce>d__"; //program.EntryMethod = "Produce"; } program.MethodUnderAnalysisName = "MoveNext"; IEnumerable <Tuple <MethodDefinition, MethodDefinition, MethodDefinition> > scopeMethodPairs; if (useScopeFactory) { scopeMethodPairs = program.ObtainScopeMethodsToAnalyze(); if (!scopeMethodPairs.Any()) { if (outputStream != null) { outputStream.WriteLine("Failed to obtain methods from the ScopeFactory. "); } System.Console.WriteLine("Failed to obtain methods from the ScopeFactory."); //System.Console.WriteLine("Now trying to find methods in the the assembly"); //scopeMethodPairs = program.ObtainScopeMethodsToAnalyzeFromAssemblies(); } } else { scopeMethodPairs = program.ObtainScopeMethodsToAnalyzeFromAssemblies(); } if (scopeMethodPairs.Any()) { var log = CreateSarifOutput(); IReadOnlyDictionary <string, Tuple <Schema, Schema> > allSchemas; if (useScopeFactory) { allSchemas = program.ReadSchemasFromXML(inputPath); } else { allSchemas = program.ReadSchemasFromXML2(inputPath); } foreach (var methodPair in scopeMethodPairs) { AnalysisStats.TotalMethods++; var entryMethodDef = methodPair.Item1; var moveNextMethod = methodPair.Item2; var getEnumMethod = methodPair.Item3; System.Console.WriteLine("Method {0} on class {1}", moveNextMethod.Name, moveNextMethod.ContainingType.FullPathName()); Schema inputSchema = null; Schema outputSchema = null; Tuple <Schema, Schema> schemas; if (allSchemas.TryGetValue(moveNextMethod.ContainingType.ContainingType.Name, out schemas)) { inputSchema = schemas.Item1; outputSchema = schemas.Item2; } try { InputSchema = inputSchema; OutputSchema = outputSchema; var dependencyAnalysis = new SongTaoDependencyAnalysis(host, program.interprocAnalysisManager, moveNextMethod, entryMethodDef, getEnumMethod); var depAnalysisResult = dependencyAnalysis.AnalyzeMoveNextMethod(); WriteResultToSarifLog(inputPath, outputStream, log, moveNextMethod, depAnalysisResult, dependencyAnalysis, program.factoryReducerMap); InputSchema = null; OutputSchema = null; } catch (Exception e) { System.Console.WriteLine("Could not analyze {0}", inputPath); System.Console.WriteLine("Exception {0}\n{1}", e.Message, e.StackTrace); AnalysisStats.TotalofDepAnalysisErrors++; AnalysisStats.AddAnalysisReason(new AnalysisReason(moveNextMethod, moveNextMethod.Body.Instructions[0], String.Format(CultureInfo.InvariantCulture, "Throw exception {0}\n{1}", e.Message, e.StackTrace.ToString()))); } } return(log); } else { System.Console.WriteLine("No method {0} of type {1} in {2}", program.MethodUnderAnalysisName, program.ClassFilters, inputPath); return(null); } }