All Downloads are FREE. Search and download functionalities are using the official Maven repository.

proguard.analysis.cpa.jvm.cfa.JvmCfa Maven / Gradle / Ivy

Go to download

ProGuardCORE is a free library to read, analyze, modify, and write Java class files.

There is a newer version: 9.1.7
Show newest version
/*
 * ProGuardCORE -- library to process Java bytecode.
 *
 * Copyright (c) 2002-2022 Guardsquare NV
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package proguard.analysis.cpa.jvm.cfa;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import proguard.analysis.datastructure.callgraph.Call;
import proguard.analysis.datastructure.callgraph.ConcreteCall;
import proguard.classfile.Clazz;
import proguard.classfile.MethodSignature;
import proguard.analysis.cpa.defaults.Cfa;
import proguard.analysis.cpa.interfaces.CfaNode;
import proguard.analysis.cpa.jvm.cfa.edges.JvmCallCfaEdge;
import proguard.analysis.cpa.jvm.cfa.edges.JvmCfaEdge;
import proguard.analysis.cpa.jvm.cfa.nodes.JvmCatchCfaNode;
import proguard.analysis.cpa.jvm.cfa.nodes.JvmCfaNode;
import proguard.analysis.cpa.jvm.cfa.nodes.JvmUnknownCfaNode;

/**
 * A JVM specific implementation of {@link Cfa}.
 *
 * 

The keys of the function maps are the {@link MethodSignature}s. * *

The nodes of a function are identified by the offset of the code location. Besides the normal exit node for return instructions, function can also have a special exit * node for uncaught exceptions. * *

An additional {@link JvmCatchCfaNode} is added for each handler in the method exception table. * *

A unique {@link JvmUnknownCfaNode} node is used for instructions the successor of which is unknown. * * @author Carlo Alberto Pozzoli */ public class JvmCfa extends Cfa { private final Map> functionCatchNodes = new HashMap<>(); /** * Returns all the catch nodes of a specific method, returns an empty collection if the function is not in the graph or if it has no catch nodes. * * @param signature The signature of the method. */ public Collection getFunctionCatchNodes(MethodSignature signature) { return functionCatchNodes.getOrDefault(signature, Collections.emptyMap()).values(); } /** * Returns the catch node of a method the handler of which begins at the specific code offset, returns null if the method or the specific catch node are not in the graph. * * @param signature The signature of the method, might be different for different domains. * @param offset The offset of the catch handler represented by the node. */ public JvmCatchCfaNode getFunctionCatchNode(MethodSignature signature, int offset) { return functionCatchNodes.getOrDefault(signature, Collections.emptyMap()).getOrDefault(offset, null); } /** * Adds a catch node to the CFA (i.e. a node indicating the beginning of an exception handler). */ public void addFunctionCatchNode(MethodSignature signature, JvmCatchCfaNode node, int offset) { functionCatchNodes.computeIfAbsent(signature, x -> new HashMap<>()).put(offset, node); allNodes.add(node); } /** * Returns true if the catch node of the specified method at the specified offset is present in the graph. */ public boolean containsFunctionCatchNode(MethodSignature signature, int offset) { return functionCatchNodes.containsKey(signature) && functionCatchNodes.get(signature).containsKey(offset); } /** * Returns the exit node of the specified method if present, otherwise creates the exit node for the method and returns it. */ public JvmCfaNode getFunctionReturnExitNode(MethodSignature signature, Clazz clazz) { // get the return exit location node JvmCfaNode exitNode = getFunctionNode(signature, CfaNode.RETURN_EXIT_NODE_OFFSET); if (exitNode == null) { exitNode = new JvmCfaNode(signature, CfaNode.RETURN_EXIT_NODE_OFFSET, clazz); addFunctionNode(signature, exitNode, CfaNode.RETURN_EXIT_NODE_OFFSET); } return exitNode; } /** * Returns the exception exit node (i.e. the exit node in case of not caught exception) of the specified method if present, otherwise creates the exit node for the method and returns it. */ public JvmCfaNode getFunctionExceptionExitNode(MethodSignature signature, Clazz clazz) { // get the exit location node JvmCfaNode exitNode = getFunctionNode(signature, CfaNode.EXCEPTION_EXIT_NODE_OFFSET); if (exitNode == null) { exitNode = new JvmCfaNode(signature, CfaNode.EXCEPTION_EXIT_NODE_OFFSET, clazz); addFunctionNode(signature, exitNode, CfaNode.EXCEPTION_EXIT_NODE_OFFSET); } return exitNode; } /** * If the requested function node is present in the graph return it. If the node is not present add it to the graph and return the new node. */ public JvmCfaNode addNodeIfAbsent(MethodSignature signature, int offset, Clazz clazz) { // if the location at the current offset is already in the CFA (e.g. created by a branch or goto) retrieve it, otherwise create a new node JvmCfaNode node = getFunctionNode(signature, offset); if (node == null) { node = new JvmCfaNode(signature, offset, clazz); // add the new node to the CFA if (offset == 0) { // first node of the functions' graph addFunctionEntryNode(signature, node); } else { addFunctionNode(signature, node, offset); } } return node; } /** * Adds a call node between two methods. */ public void addInterproceduralEdge(Call call) { JvmCfaNode callNode = addNodeIfAbsent(((MethodSignature) call.caller.signature), call.caller.offset, call.caller.clazz); JvmCfaNode calledNode = addNodeIfAbsent(call.getTarget(), 0, call instanceof ConcreteCall ? ((ConcreteCall) call).getTargetClass() : null); new JvmCallCfaEdge(callNode, calledNode, call); } /** * Adds a call node between two methods. This is used when the target method has no {@link proguard.classfile.attribute.CodeAttribute}, which means the target method is not present in the CFA. The * unknown node is set as the call target. */ public void addUnknownTargetInterproceduralEdge(Call call) { JvmCfaNode callNode = addNodeIfAbsent(((MethodSignature) call.caller.signature), call.caller.offset, call.caller.clazz); JvmCfaNode calledNode = JvmUnknownCfaNode.INSTANCE; new JvmCallCfaEdge(callNode, calledNode, call); } /** * Removes references to this CFA nodes from the singleton {@link JvmUnknownCfaNode} and clears its node collections making it garbage collectable. */ public void clear() { JvmUnknownCfaNode.INSTANCE.getEnteringEdges().removeIf(e -> allNodes.contains(e.getSource())); functionCatchNodes.clear(); functionNodes.clear(); allNodes.clear(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy