/* * Copyright (c) 2010-2015 SAP SE. * 2016-2018 The University of Sheffield. * * All rights reserved. This program and the accompanying materials * This program and the accompanying materials are made * available under the terms of the Eclipse Public License 2.0 * which is available at https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 */ package com.logicalhacking.dasca.crosslanguage.builder.algorithms import scala.collection.JavaConverters.asScalaIteratorConverter import scala.collection.mutable.Queue import scala.collection.JavaConverters._ import org.slf4j.LoggerFactory import com.ibm.wala.ipa.callgraph.CGNode import com.ibm.wala.ipa.callgraph.CallGraph import com.ibm.wala.ipa.cfg.BasicBlockInContext import com.ibm.wala.ipa.cfg.ExplodedInterproceduralCFG import com.ibm.wala.ssa.SSAInstruction import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph import com.ibm.wala.ssa.analysis.IExplodedBasicBlock import com.typesafe.scalalogging.Logger import scala.collection.mutable.ListBuffer import com.ibm.wala.ssa.SSAAbstractInvokeInstruction abstract class ReachabilityChecker(private val cg: CallGraph, private val keep: CGNode => Boolean) { val logger = Logger(LoggerFactory.getLogger(getClass.toString)) val cache = scala.collection.mutable.Map[(CGNode, CGNode, SSAInstruction), Boolean]() def isReachable(fromNode: CGNode, toNode: CGNode, inst: SSAInstruction): Boolean = { if (cache.contains((fromNode, toNode, inst))) return cache((fromNode, toNode, inst)) val instructions = if (fromNode == toNode) { List(inst) } else { getReachableInstructions(fromNode, toNode) } val ecfg = ExplodedControlFlowGraph.make(fromNode.getIR) val res = instructions.exists { inst => isReachable(ecfg, inst) } cache((fromNode, toNode, inst)) = res res } def getReachableInstructions(fromNode: CGNode, toNode: CGNode): List[SSAInstruction] = { val lb = ListBuffer[SSAInstruction]() if (!keep(fromNode) || !keep(toNode)) return List() val queue = Queue[CGNode](toNode) val visited = scala.collection.mutable.Set[CGNode]() while (!queue.isEmpty) { val cur = queue.dequeue() if (!visited.contains(cur)) { visited += cur for (pred <- cg.getPredNodes(cur).asScala ++ extraPredNodes(cur) if keep(pred)) { if (pred == fromNode) { for (csr <- cg.getPossibleSites(pred, cur).asScala; invoke <- pred.getIR.getCalls(csr)) { lb += invoke } } else { queue += pred } } } } lb.toList } private def isReachable(ecfg: ExplodedControlFlowGraph, inst: SSAInstruction): Boolean = { ecfg.getBlockForInstruction(inst.iindex) val queue = Queue[IExplodedBasicBlock](ecfg.getBlockForInstruction(inst.iindex)) val visited = scala.collection.mutable.Set[IExplodedBasicBlock]() while (!queue.isEmpty) { val cur = queue.dequeue() if (!visited.contains(cur)) { visited += cur if (cur == ecfg.entry()) return true for (pred <- ecfg.getPredNodes(cur).asScala if canPassThrough(cur, pred)) { queue += pred } } } return false } def extraPredNodes(node: CGNode): List[CGNode] def canPassThrough(toBB: IExplodedBasicBlock, predBB: IExplodedBasicBlock): Boolean }