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

boomerang.QueryGraph Maven / Gradle / Ivy

There is a newer version: 3.2.2
Show newest version
package boomerang;

import boomerang.callgraph.CallerListener;
import boomerang.callgraph.ObservableICFG;
import boomerang.scene.ControlFlowGraph;
import boomerang.scene.ControlFlowGraph.Edge;
import boomerang.scene.Method;
import boomerang.scene.Statement;
import boomerang.scene.Val;
import boomerang.solver.AbstractBoomerangSolver;
import boomerang.solver.BackwardBoomerangSolver;
import boomerang.solver.ForwardBoomerangSolver;
import boomerang.util.DefaultValueMap;
import com.google.common.base.Joiner;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sync.pds.solver.nodes.GeneratedState;
import sync.pds.solver.nodes.INode;
import sync.pds.solver.nodes.Node;
import sync.pds.solver.nodes.SingleNode;
import wpds.impl.Transition;
import wpds.impl.Weight;
import wpds.impl.WeightedPAutomaton;
import wpds.interfaces.WPAStateListener;

public class QueryGraph {
  private static final Logger LOGGER = LoggerFactory.getLogger(QueryGraph.class);
  private final ObservableICFG icfg;
  private Multimap sourceToQueryEdgeLookUp = HashMultimap.create();
  private Multimap targetToQueryEdgeLookUp = HashMultimap.create();
  private Set roots = Sets.newHashSet();
  private DefaultValueMap> forwardSolvers;
  private Multimap edgeAddListener = HashMultimap.create();
  private DefaultValueMap> backwardSolver;

  public QueryGraph(WeightedBoomerang weightedBoomerang) {
    this.forwardSolvers = weightedBoomerang.getSolvers();
    this.backwardSolver = weightedBoomerang.getBackwardSolvers();
    this.icfg = weightedBoomerang.icfg;
  }

  public void addRoot(Query root) {
    this.roots.add(root);
  }

  public void addEdge(Query parent, Node node, Query child) {
    QueryEdge queryEdge = new QueryEdge(parent, node, child);
    sourceToQueryEdgeLookUp.put(parent, queryEdge);
    if (targetToQueryEdgeLookUp.put(child, queryEdge)) {
      for (AddTargetEdgeListener l : Lists.newArrayList(edgeAddListener.get(child))) {
        l.edgeAdded(queryEdge);
      }
    }
    getSolver(parent)
        .getCallAutomaton()
        .registerListener(new SourceListener(new SingleNode<>(node.fact()), parent, child, null));
  }

  private AbstractBoomerangSolver getSolver(Query query) {
    if (query instanceof BackwardQuery) {
      return backwardSolver.get(query);
    }
    return forwardSolvers.get(query);
  }

  public void unregisterAllListeners() {
    this.edgeAddListener.clear();
  }

  public Set getNodes() {
    Set nodes = Sets.newHashSet(sourceToQueryEdgeLookUp.keySet());
    nodes.addAll(targetToQueryEdgeLookUp.keySet());
    return nodes;
  }

  private class SourceListener extends WPAStateListener, W> {

    private Query child;
    private Query parent;
    private Method callee;

    public SourceListener(INode state, Query parent, Query child, Method callee) {
      super(state);
      this.parent = parent;
      this.child = child;
      this.callee = callee;
    }

    @Override
    public void onOutTransitionAdded(
        Transition> t,
        W w,
        WeightedPAutomaton, W> weightedPAutomaton) {
      if (t.getStart() instanceof GeneratedState && callee != null) {
        Edge callSiteLabel = t.getLabel();
        getSolver(child)
            .allowUnbalanced(
                callee,
                (parent instanceof BackwardQuery
                    ? callSiteLabel.getTarget()
                    : callSiteLabel.getStart()));
      }
      if (t.getTarget() instanceof GeneratedState) {
        getSolver(parent)
            .getCallAutomaton()
            .registerListener(
                new SourceListener(t.getTarget(), parent, child, t.getLabel().getMethod()));
      }

      if (weightedPAutomaton.isUnbalancedState(t.getTarget())) {
        registerEdgeListener(new UnbalancedContextListener(child, parent, t));
      }
    }

    @Override
    public void onInTransitionAdded(
        Transition> t,
        W w,
        WeightedPAutomaton, W> weightedPAutomaton) {}

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = super.hashCode();
      result = prime * result + getEnclosingInstance().hashCode();
      result = prime * result + ((callee == null) ? 0 : callee.hashCode());
      result = prime * result + ((child == null) ? 0 : child.hashCode());
      result = prime * result + ((parent == null) ? 0 : parent.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) return true;
      if (!super.equals(obj)) return false;
      if (getClass() != obj.getClass()) return false;
      SourceListener other = (SourceListener) obj;
      if (!getEnclosingInstance().equals(other.getEnclosingInstance())) return false;
      if (callee == null) {
        if (other.callee != null) return false;
      } else if (!callee.equals(other.callee)) return false;
      if (child == null) {
        if (other.child != null) return false;
      } else if (!child.equals(other.child)) return false;
      if (parent == null) {
        if (other.parent != null) return false;
      } else if (!parent.equals(other.parent)) return false;
      return true;
    }

    private QueryGraph getEnclosingInstance() {
      return QueryGraph.this;
    }
  }

  public String toString() {
    String s = "";
    int level = 0;
    for (Query root : roots) {
      s += "Root:" + root + "\n";
      s += visit(root, "", ++level, Sets.newHashSet());
    }
    return s;
  }

  public void registerEdgeListener(AddTargetEdgeListener l) {
    if (edgeAddListener.put(l.getTarget(), l)) {
      ArrayList edges = Lists.newArrayList(targetToQueryEdgeLookUp.get(l.getTarget()));
      for (QueryEdge edge : edges) {
        l.edgeAdded(edge);
      }
      if (edges.isEmpty()) {
        l.noParentEdge();
      }
    }
  }

  private interface AddTargetEdgeListener {
    Query getTarget();

    void edgeAdded(QueryEdge queryEdge);

    void noParentEdge();
  }

  private class UnbalancedContextListener implements AddTargetEdgeListener {

    private final Transition> transition;
    private Query parent;
    private Query child;

    public UnbalancedContextListener(Query child, Query parent, Transition> t) {
      this.child = child;
      this.parent = parent;
      this.transition = t;
    }

    @Override
    public Query getTarget() {
      return parent;
    }

    @Override
    public void edgeAdded(QueryEdge parentOfParent) {
      Query newParent = parentOfParent.getSource();
      getSolver(newParent)
          .getCallAutomaton()
          .registerListener(
              new SourceListener(
                  new SingleNode<>(parentOfParent.getNode().fact()), newParent, child, null));
    }

    @Override
    public void noParentEdge() {
      if (child instanceof BackwardQuery) {
        Method callee = transition.getTarget().fact().m();
        icfg.addCallerListener(
            new CallerListener() {
              @Override
              public Method getObservedCallee() {
                return callee;
              }

              @Override
              public void onCallerAdded(Statement callSite, Method method) {
                getSolver(child).allowUnbalanced(callee, callSite);
              }
            });
      }
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + getEnclosingInstance().hashCode();
      result = prime * result + ((child == null) ? 0 : child.hashCode());
      result = prime * result + ((parent == null) ? 0 : parent.hashCode());
      result = prime * result + ((transition == null) ? 0 : transition.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) return true;
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      UnbalancedContextListener other = (UnbalancedContextListener) obj;
      if (!getEnclosingInstance().equals(other.getEnclosingInstance())) return false;
      if (child == null) {
        if (other.child != null) return false;
      } else if (!child.equals(other.child)) return false;
      if (parent == null) {
        if (other.parent != null) return false;
      } else if (!parent.equals(other.parent)) return false;
      if (parent == null) {
        if (other.transition != null) return false;
      } else if (!transition.equals(other.transition)) return false;
      return true;
    }

    private QueryGraph getEnclosingInstance() {
      return QueryGraph.this;
    }
  }

  private String visit(Query parent, String s, int i, Set visited) {
    for (QueryEdge child : sourceToQueryEdgeLookUp.get(parent)) {
      if (visited.add(child.getTarget())) {
        for (int j = 0; j <= i; j++) {
          s += " ";
        }
        s += i;
        s += child + "\n";
        s += visit(child.getTarget(), "", ++i, visited);
      } else {
      }
    }
    return s;
  }

  public String toDotString() {
    String s = "digraph {\n";
    TreeSet trans = new TreeSet();
    for (Entry target : sourceToQueryEdgeLookUp.entries()) {
      String v = "\t\"" + escapeQuotes(target.getKey().toString()) + "\"";
      v += " -> \"" + escapeQuotes(target.getValue().getTarget().toString()) + "\"";
      trans.add(v);
    }

    s += Joiner.on("\n").join(trans);
    s += "}\n";
    return s;
  }

  private String escapeQuotes(String string) {
    return string.replace("\"", "");
  }

  private static class QueryEdge {
    private final Query source;
    private final Query target;
    private Node node;

    public QueryEdge(Query source, Node node, Query target) {
      this.source = source;
      this.node = node;
      this.target = target;
    }

    public Node getNode() {
      return node;
    }

    public Query getSource() {
      return source;
    }

    public Query getTarget() {
      return target;
    }

    @Override
    public int hashCode() {
      final int prime = 31;
      int result = 1;
      result = prime * result + ((source == null) ? 0 : source.hashCode());
      result = prime * result + ((node == null) ? 0 : node.hashCode());
      result = prime * result + ((target == null) ? 0 : target.hashCode());
      return result;
    }

    @Override
    public boolean equals(Object obj) {
      if (this == obj) return true;
      if (obj == null) return false;
      if (getClass() != obj.getClass()) return false;
      QueryEdge other = (QueryEdge) obj;
      if (source == null) {
        if (other.source != null) return false;
      } else if (!source.equals(other.source)) return false;
      if (target == null) {
        if (other.target != null) return false;
      } else if (!target.equals(other.target)) return false;
      if (node == null) {
        if (other.node != null) return false;
      } else if (!node.equals(other.node)) return false;
      return true;
    }
  }

  public boolean isRoot(Query q) {
    return roots.contains(q);
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy