private void ComputeMethodCfg(MethodDefinition method)
        {
            var methodName = method.GetCompatibleFullName();

            if (Cfg.Procs.ContainsKey(methodName))
            {
                Log.WriteWarning($"Method with duplicate full name found: {methodName }");
                return;
            }

            var programState = new ProgramState(method, Cfg);

            var methodBody = method.Body;

            // True if the translation terminates early, false otherwise.
            var translationUnfinished = false;

            if (!method.IsAbstract && methodBody.Instructions.Count > 0)
            {
                programState.PushInstruction(methodBody.Instructions.First());
                do
                {
                    var nextInstruction = programState.PopInstruction();
                    // Checks if there is a node for the offset that we can reuse.
                    (var nodeAtOffset, var excessiveVisits) =
                        programState.GetOffsetNode(nextInstruction.Offset);
                    if (nodeAtOffset != null)
                    {
                        programState.PreviousNode.Successors.Add(nodeAtOffset);
                    }
                    else if (excessiveVisits)
                    {
                        TimeoutMethodCount++;
                        Log.WriteError("Translation timeout.");
                        Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(),
                                                   nextInstruction.RemainingInstructionCount());
                        translationUnfinished = true;
                        break;
                    }
                    else if (!InstructionParser.ParseCilInstruction(nextInstruction, programState))
                    {
                        Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(),
                                                   nextInstruction.RemainingInstructionCount());
                        translationUnfinished = true;
                        break;
                    }
                } while (programState.HasInstruction);
            }

            // We add method to cfg only if its translation is finished. Otherwise, we skip that method.
            if (translationUnfinished && !IsDisposeFunction(method))
            {
                // Deregisters resources of skipped method.
                programState.ProcDesc.DeregisterResources(Cfg);
            }
            else
            {
                // Sets exception sink node as default exception node for all nodes in the graph.
                foreach (var node in programState.ProcDesc.Nodes)
                {
                    node.ExceptionNodes.Add(programState.ProcDesc.ExceptionSinkNode);
                }

                // Exception node for start and exception sink should be exit, exception node for exit
                // should be empty.
                programState.ProcDesc.StartNode.ExceptionNodes.Clear();
                programState.ProcDesc.ExitNode.ExceptionNodes.Clear();
                programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Clear();
                programState.ProcDesc.StartNode.ExceptionNodes.Add(programState.ProcDesc.ExitNode);
                programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Add(
                    programState.ProcDesc.ExitNode);

                SetNodePredecessors(programState);

                Cfg.Procs.Add(methodName, programState.ProcDesc);
            }
        }
Пример #2
0
        private void ComputeMethodCfg(MethodDefinition method)
        {
            var methodName = method.GetCompatibleFullName();

            if (Cfg.Procs.ContainsKey(methodName))
            {
                Log.WriteWarning($"Method with duplicate full name found: {methodName }");
                return;
            }

            var programState = new ProgramState(method, Cfg);

            var methodBody             = method.Body;
            var unhandledExceptionCase =
                programState.MethodExceptionHandlers.UnhandledExceptionBlock ||
                !programState.MethodExceptionHandlers.NoNestedTryCatchFinally() ||
                !programState.MethodExceptionHandlers.NoFinallyEndWithThrow();

            // True if the translation terminates early, false otherwise.
            var translationUnfinished = false;

            if (!method.IsAbstract && methodBody.Instructions.Count > 0)
            {
                programState.PushInstruction(methodBody.Instructions.First());
                do
                {
                    var nextInstruction = programState.PopInstruction();
                    // Checks if there is a node for the offset that we can reuse.
                    (var nodeAtOffset, var excessiveVisits) =
                        programState.GetOffsetNode(
                            nextInstruction.Offset,
                            programState.PreviousNode?.BlockEndOffset ??
                            MethodExceptionHandlers.DefaultHandlerEndOffset);
                    // We don't reuse nodes of finally handlers.
                    if (nodeAtOffset != null &&
                        !programState.MethodExceptionHandlers
                        .FinallyOffsetToFinallyHandler
                        .ContainsKey(nextInstruction.Offset) &&
                        !programState.MethodExceptionHandlers
                        .CatchOffsetToCatchHandler
                        .ContainsKey(nextInstruction.Offset))
                    {
                        programState.PreviousNode.Successors.Add(nodeAtOffset);
                    }
                    else if (unhandledExceptionCase)
                    {
                        Log.WriteWarning($"Unhandled exception-handling.");
                        Log.RecordUnknownInstruction("unhandled-exception");
                        Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(),
                                                   nextInstruction.RemainingInstructionCount());
                        translationUnfinished = true;
                        break;
                    }
                    else if (excessiveVisits)
                    {
                        TimeoutMethodCount++;
                        Log.WriteWarning("Translation timeout.");
                        Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(),
                                                   nextInstruction.RemainingInstructionCount());
                        translationUnfinished = true;
                        break;
                    }
                    else if (!InstructionParser.ParseCilInstruction(nextInstruction, programState))
                    {
                        Log.RecordUnfinishedMethod(programState.Method.GetCompatibleFullName(),
                                                   nextInstruction.RemainingInstructionCount());
                        translationUnfinished = true;
                        break;
                    }
                } while (programState.HasInstruction);
            }

            // We add method to cfg only if its translation is finished. Otherwise, we skip that
            // method.
            if (translationUnfinished && !IsDisposeFunction(method))
            {
                // Deregisters resources of skipped method.
                programState.ProcDesc.DeregisterResources(Cfg);
            }
            else
            {
                // Sets exception sink node as default exception node for all nodes in the graph.
                foreach (var node in programState.ProcDesc.Nodes)
                {
                    // Nodes linked with exception handlers should not be linked with the sink, and
                    // will already have the corresponding nodes linked.
                    if (node.ExceptionNodes.Count == 0)
                    {
                        node.ExceptionNodes.Add(programState.ProcDesc.ExceptionSinkNode);
                    }
                }

                // Exception node for start and exception sink should be exit, exception node for exit
                // should be empty.
                programState.ProcDesc.StartNode.ExceptionNodes.Clear();
                programState.ProcDesc.ExitNode.ExceptionNodes.Clear();
                programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Clear();
                programState.ProcDesc.StartNode.ExceptionNodes.Add(programState.ProcDesc.ExitNode);
                programState.ProcDesc.ExceptionSinkNode.ExceptionNodes.Add(
                    programState.ProcDesc.ExitNode);

                SetNodePredecessors(programState);

                Cfg.Procs.Add(methodName, programState.ProcDesc);
            }
        }