Ejemplo n.º 1
0
        public void RemoveSameClasses()
        {
            var handledNodes    = new HashSet <ICallGraphNode>(Nodes.Count);
            var processingNodes = new Queue <(ICallGraphNode, ICallGraphNode)>();

            EntryNodes.Clear();
            Nodes.Clear();
            var roots = Roots.Values;

            Roots = new Dictionary <MethodUniqueSignature, ICallGraphNode>();
            foreach (var rootNode in roots)
            {
                // we keep all parents of root(s)
                if (!handledNodes.Add(rootNode))
                {
                    continue;
                }

                var mappedRootNode = new CallInfoNode(rootNode.Info);
                Roots.Add(mappedRootNode.MethodSignature, mappedRootNode);
                Nodes.Add(mappedRootNode.MethodSignature, mappedRootNode);
                if (rootNode.InNodes.Count == 0 && !EntryNodes.ContainsKey(mappedRootNode.MethodSignature))
                {
                    EntryNodes.Add(mappedRootNode.MethodSignature, mappedRootNode);
                }

                foreach (var inNode in rootNode.InNodes)
                {
                    var mappedNode = new CallInfoNode(inNode.Info);
                    mappedRootNode.InNodes.Add(mappedNode);
                    mappedNode.OutNodes.Add(mappedRootNode);

                    if (!Nodes.ContainsKey(mappedNode.MethodSignature))
                    {
                        Nodes.Add(mappedNode.MethodSignature, mappedNode);
                        if (inNode.InNodes.Count == 0)
                        {
                            if (!EntryNodes.ContainsKey(mappedNode.MethodSignature))
                            {
                                EntryNodes.Add(mappedNode.MethodSignature, mappedNode);
                            }
                        }
                        else
                        {
                            processingNodes.Enqueue((inNode, mappedNode));
                        }
                    }
                }
            }

            // and keep only different classes for other parents
            while (processingNodes.Count > 0)
            {
                var(node, mappedNode) = processingNodes.Dequeue();
                if (!handledNodes.Add(node))
                {
                    continue;
                }

                var mappedInNodes = new HashSet <ICallGraphNode>(mappedNode.InNodes);
                foreach (var inNode in node.InNodes)
                {
                    var classSignature = new MethodUniqueSignature(inNode.MethodSignature.ToClassName());
                    if (Nodes.TryGetValue(classSignature, out var mappedInNode))
                    {
                        if (mappedInNode != mappedNode && mappedInNodes.Add(mappedInNode))
                        {
                            mappedInNode.OutNodes.Add(mappedNode);
                        }
                    }
                    else
                    {
                        mappedInNode = new CallInfoNode(new CallInfo(
                                                            0,
                                                            null,
                                                            inNode.AssemblyInfo,
                                                            classSignature,
                                                            inNode.IsPublic,
                                                            null));

                        mappedInNodes.Add(mappedInNode);
                        mappedInNode.OutNodes.Add(mappedNode);
                        Nodes.Add(mappedInNode.MethodSignature, mappedInNode);
                    }

                    if (inNode.InNodes.Count == 0)
                    {
                        if (!EntryNodes.ContainsKey(mappedInNode.MethodSignature))
                        {
                            EntryNodes.Add(mappedInNode.MethodSignature, mappedInNode);
                        }
                    }
                    else
                    {
                        processingNodes.Enqueue((inNode, mappedInNode));
                    }
                }

                if (mappedNode.InNodes.Count != mappedInNodes.Count)
                {
                    mappedNode.InNodes.Clear();
                    mappedNode.InNodes.AddRange(mappedInNodes);
                }
            }
        }
Ejemplo n.º 2
0
        private CallGraph CreateGraphInternal(List <TemplateInfo> templates)
        {
            var graph = new CallGraph();
            var processingEntities = new Queue <ProcessingEntity>();

            foreach (var template in templates)
            {
                var calls = index.GetCalls(template);
                if (calls.Count > 0)
                {
                    // HACK if we found call w/ version restriction
                    // then we add it and find again w/o version restrictions
                    // in practice the result should be the same (but not always)
                    var info = CallInfo.CreateFake(
                        new AssemblyInfo(UTF8String.Empty, template.RequiredOlderVersion),
                        template.Method);
                    var node = new CallInfoNode(info);
                    graph.Nodes.Add(template.Method, node);
                    graph.Roots.Add(template.Method, node);
                    processingEntities.Enqueue(new ProcessingEntity(node.MethodSignature, node));
                }
            }

            while (processingEntities.Count > 0)
            {
                var entity = processingEntities.Dequeue();

                var calls = index.GetCalls(entity.Signature /*, entity.Node.AssemblyInfo*/);
                if (calls.Count != 0)
                {
                    foreach (var callInfo in calls)
                    {
                        if (callInfo.Opcode.Code != Code.Call &&
                            callInfo.Opcode.Code != Code.Callvirt &&
                            callInfo.Opcode.Code != Code.Newobj &&
                            callInfo.Opcode.Code != Code.Ldtoken)          // used into Expression Tree in KB, need to implement DFA
                        //resume.Opcode.Code != Code.Ldvirtftn &&    // can use with calli
                        //resume.Opcode.Code != Code.Ldftn)          // https://docs.microsoft.com/en-us/dotnet/api/system.reflection.emit.opcodes.calli?view=netframework-4.7.2
                        {
                            // just ignore it for now, need to implement DFA
                            stat.IgnoredOpcodes.Add(callInfo.Opcode.Code);
                            continue;
                        }

                        if (entity.VirtCallRequired && callInfo.Opcode.Code != Code.Callvirt)
                        {
                            continue;
                        }

                        if (graph.Nodes.TryGetValue(callInfo.Signature, out var callingNode))
                        {
                            // TODO: need to add a new kind of cycled edge to remove recursive calls in RemoveNonPublicEntryNodes
                            //callingNode.OutNodes.Add(entity.Node);
                            //entity.Node.InNodes.Add(callingNode);
                        }
                        else
                        {
                            callingNode = new CallInfoNode(callInfo);
                            callingNode.OutNodes.Add(entity.Node);
                            entity.Node.InNodes.Add(callingNode);

                            graph.Nodes.Add(callInfo.Signature, callingNode);
                            processingEntities.Enqueue(new ProcessingEntity(callInfo.Signature, callingNode));

                            foreach (var overrideSignature in callInfo.OverrideSignatures)
                            {
                                processingEntities.Enqueue(new ProcessingEntity(overrideSignature, callingNode, true));
                            }
                        }
                    }
                }
            }

            foreach (var node in graph.Nodes.Values)
            {
                if (node.InNodes.Count != 0)
                {
                    continue;
                }

                graph.EntryNodes.Add(node.MethodSignature, node);
            }

            return(graph);
        }