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

sootup.analysis.interprocedural.icfg.JimpleBasedInterproceduralCFG Maven / Gradle / Ivy

There is a newer version: 1.3.0
Show newest version
package sootup.analysis.interprocedural.icfg;

/*-
 * #%L
 * Soot - a J*va Optimization Framework
 * %%
 * Copyright (C) 2022 Kadiray Karakaya and others
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation, either version 2.1 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Lesser Public License for more details.
 *
 * You should have received a copy of the GNU General Lesser Public
 * License along with this program.  If not, see
 * .
 * #L%
 */

import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import heros.DontSynchronize;
import heros.InterproceduralCFG;
import heros.SynchronizedBy;
import heros.ThreadSafe;
import heros.solver.IDESolver;
import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sootup.callgraph.CallGraph;
import sootup.callgraph.CallGraphAlgorithm;
import sootup.callgraph.ClassHierarchyAnalysisAlgorithm;
import sootup.core.graph.StmtGraph;
import sootup.core.jimple.common.stmt.Stmt;
import sootup.core.model.SootMethod;
import sootup.core.signatures.MethodSignature;
import sootup.core.views.View;

/**
 * Default implementation for the {@link InterproceduralCFG} interface. Includes all statements
 * reachable from entrypoints through explicit call statements or through calls to {@link
 * Thread#start()}.
 *
 * 

This class is designed to be thread safe, and subclasses of this class must be designed in a * thread-safe way, too. */ @ThreadSafe public class JimpleBasedInterproceduralCFG extends AbstractJimpleBasedICFG { protected static final Logger logger = LoggerFactory.getLogger(JimpleBasedInterproceduralCFG.class); private final MethodSignature mainMethodSignature; protected boolean includeReflectiveCalls; @DontSynchronize("readonly") protected final CallGraph cg; protected CacheLoader> loaderUnitToCallees = new CacheLoader>() { @Nonnull @Override public Collection load(Stmt stmt) { ArrayList res = new ArrayList<>(); MethodSignature methodSignature = stmt.getInvokeExpr().getMethodSignature(); Optional smOpt = view.getMethod(methodSignature); if (smOpt.isPresent()) { SootMethod sm = smOpt.get(); if (sm.hasBody()) { res.add(sm); } else { logger.error( "Method {} is referenced but has no body!", sm.getSignature(), new Exception()); } } res.trimToSize(); return res; } }; @SynchronizedBy("by use of synchronized LoadingCache class") protected final LoadingCache> stmtToCallees = IDESolver.DEFAULT_CACHE_BUILDER.build(loaderUnitToCallees); protected CacheLoader> loaderMethodToCallers = new CacheLoader>() { @Nonnull @Override public Collection load(SootMethod method) { ArrayList res = new ArrayList<>(); // only retain callers that are explicit call sites or // Thread.start() Set callsToMethod = cg.callsTo(method.getSignature()); for (MethodSignature methodSignature : callsToMethod) { Stmt stmt = filterEdgeAndGetCallerStmt(methodSignature); if (stmt != null) { res.add(stmt); } } res.trimToSize(); return res; } @Nullable private Stmt filterEdgeAndGetCallerStmt(@Nonnull MethodSignature methodSignature) { Set> callEdges = CGEdgeUtil.getCallEdges(view, cg); for (Pair callEdge : callEdges) { CalleeMethodSignature callee = callEdge.getValue(); if (callee.getMethodSignature().equals(methodSignature)) { CGEdgeUtil.CallGraphEdgeType edgeType = callee.getEdgeType(); if (edgeType.isExplicit() || edgeType.isFake() || edgeType.isClinit() || (includeReflectiveCalls && edgeType.isReflection())) { return callee.getSourceStmt(); } } } return null; } }; @SynchronizedBy("by use of synchronized LoadingCache class") protected final LoadingCache> methodToCallers = IDESolver.DEFAULT_CACHE_BUILDER.build(loaderMethodToCallers); public JimpleBasedInterproceduralCFG( View view, MethodSignature mainMethodSignature, boolean enableExceptions, boolean includeReflectiveCalls) { super(enableExceptions); this.includeReflectiveCalls = includeReflectiveCalls; this.view = view; this.mainMethodSignature = mainMethodSignature; cg = initCallGraph(); initializeStmtToOwner(); } public String buildICFGGraph(CallGraph callGraph) { Map> signatureToStmtGraph = new LinkedHashMap<>(); computeAllCalls(mainMethodSignature, signatureToStmtGraph, callGraph); return ICFGDotExporter.buildICFGGraph(signatureToStmtGraph, view, callGraph); } public void computeAllCalls( MethodSignature methodSignature, Map> signatureToStmtGraph, CallGraph callGraph) { ArrayList visitedMethods = new ArrayList<>(); computeAllCalls(methodSignature, signatureToStmtGraph, callGraph, visitedMethods); } private void computeAllCalls( MethodSignature methodSignature, Map> signatureToStmtGraph, CallGraph callGraph, List visitedMethods) { visitedMethods.add(methodSignature); final Optional methodOpt = view.getMethod(methodSignature); // return if the methodSignature is already added to the hashMap to avoid stackoverflow error. if (signatureToStmtGraph.containsKey(methodSignature)) return; if (methodOpt.isPresent()) { SootMethod sootMethod = methodOpt.get(); if (sootMethod.hasBody()) { StmtGraph stmtGraph = sootMethod.getBody().getStmtGraph(); signatureToStmtGraph.put(methodSignature, stmtGraph); } } callGraph.callsFrom(methodSignature).stream() .filter(methodSignature1 -> !visitedMethods.contains(methodSignature1)) .forEach( nextMethodSignature -> computeAllCalls( nextMethodSignature, signatureToStmtGraph, callGraph, visitedMethods)); } private CallGraph initCallGraph() { CallGraphAlgorithm cga = new ClassHierarchyAnalysisAlgorithm(view); return cga.initialize(Collections.singletonList(mainMethodSignature)); } protected void initializeStmtToOwner() { for (MethodSignature methodSignature : cg.getMethodSignatures()) { final Optional methodOpt = view.getMethod(methodSignature); methodOpt.ifPresent(this::initializeStmtToOwner); } } @Override public Collection getCalleesOfCallAt(@Nonnull Stmt u) { return stmtToCallees.getUnchecked(u); } @Override public Collection getCallersOf(@Nonnull SootMethod m) { return methodToCallers.getUnchecked(m); } public static Set> getCallEdges( @Nonnull View view, @Nonnull CallGraph cg) { Set methodSigs = cg.getMethodSignatures(); Set> callEdges = new HashSet<>(); for (MethodSignature caller : methodSigs) { Optional methodOpt = view.getMethod(caller); if (methodOpt.isPresent()) { final SootMethod method = methodOpt.get(); if (method.hasBody()) { for (Stmt s : method.getBody().getStmtGraph().getNodes()) { if (s.containsInvokeExpr()) { CalleeMethodSignature callee = new CalleeMethodSignature( s.getInvokeExpr().getMethodSignature(), CGEdgeUtil.findCallGraphEdgeType(s.getInvokeExpr()), s); callEdges.add(new ImmutablePair<>(caller, callee)); } } } } } return callEdges; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy