Ejemplo n.º 1
0
  /**
   * Rough and simple overapproximation: cross product of all defs against all uses of a
   * field/arrayElem. This is a static approximation: only one data-dependence per field/arrayElem
   * def x use. (At runtime, there might be multiple dependences of fields of different objects or
   * different array elements.)
   */
  private void computeFieldArrayObjDUAs(
      List<SootMethod> allReachableMethods,
      Map<SootMethod, ReachableUsesDefs> methodsToReachUseDefs) {
    assert methodsToReachUseDefs.keySet().size() == allReachableMethods.size();
    assert methodsToReachUseDefs.keySet().containsAll(allReachableMethods);

    // collect all uses from cfgs
    List<Use> allFieldUses = new ArrayList<Use>();
    List<Use> allArrElemUses = new ArrayList<Use>();
    List<Use> allObjUses = new ArrayList<Use>();
    for (SootMethod m : allReachableMethods) {
      ReachableUsesDefs ru = methodsToReachUseDefs.get(m);
      allFieldUses.addAll(ru.getFieldUses());
      allArrElemUses.addAll(ru.getArrayElemUses());
      allObjUses.addAll(ru.getLibObjUses());
    }

    // sort all these uses
    List<Use> sortedFldUses = new ArrayList<Use>(allFieldUses);
    Collections.sort(sortedFldUses, new UseComparator());
    List<Use> sortedArrElemUses = new ArrayList<Use>(allArrElemUses);
    Collections.sort(sortedArrElemUses, new UseComparator());
    List<Use> sortedObjUses = new ArrayList<Use>(allObjUses);
    Collections.sort(sortedObjUses, new UseComparator());

    // match uses to defs; resolve fields for comparison (field refs are not necessarily "equal"!)
    int numFieldDUAs = 0;
    int numArrayElemDUAs = 0;
    int numObjectDUAs = 0;
    Map<SootField, List<DUA>> duasPerField = new HashMap<SootField, List<DUA>>();
    Map<Type, List<DUA>> duasPerArrElem = new HashMap<Type, List<DUA>>();
    Map<Pair<RefType, Boolean>, List<DUA>> duasPerObjType =
        new HashMap<Pair<RefType, Boolean>, List<DUA>>();
    for (SootMethod m : allReachableMethods) {
      ReachableUsesDefs ru = methodsToReachUseDefs.get(m);
      // 1. Match fields, but only if neither def or use is in catch block
      List<Def> sortedFldDefs = new ArrayList<Def>(ru.getFieldDefs());
      Collections.sort(sortedFldDefs, new DefComparator());
      for (Def fldDef : sortedFldDefs) {
        if (fldDef.isInCatchBlock()) continue;

        SootField fldD = ((FieldRef) fldDef.getValue()).getField();
        // exclude DUAs for some special fields: class (ref to Class of object), and this$0 (link to
        // container obj of nested class obj)
        if (fldD.getName().equals("class$0"))
          continue; // causes trouble when instrumenting <clinit>, where class$0 gets defined (i.e.,
                    // Class loaded on demand)
        if (fldD.getName().equals("this$0"))
          continue; // causes trouble when instrumenting code that links nested class to outer
                    // object

        for (Use fldUse : sortedFldUses) {
          if (fldUse.isInCatchBlock()) continue;

          SootField fldU = ((FieldRef) fldUse.getValue()).getField();
          if (fldD == fldU) {
            // create and store field DUA
            DUA fldDUA = new DUA(fldDef, fldUse, new Use[0], false);
            duaSet.addDUA(fldDUA);

            // associate DUA to field
            List<DUA> duasForFld = duasPerField.get(fldD);
            if (duasForFld == null) {
              duasForFld = new ArrayList<DUA>();
              duasPerField.put(fldD, duasForFld);
            }
            duasForFld.add(fldDUA);

            // update count of field DUAs
            ++numFieldDUAs;
          }
        }
      }
      // 2. Match array elements, simply by element type
      List<Def> sortedArrDefs = new ArrayList<Def>(ru.getArrayElemDefs());
      Collections.sort(sortedArrDefs, new DefComparator());
      for (Def arrElemDef : sortedArrDefs) {
        if (arrElemDef.isInCatchBlock()) continue;

        Variable varDef = arrElemDef.getVar();
        Type defArrElemType = ((ArrayRef) arrElemDef.getValue()).getType();
        for (Use arrElemUse : sortedArrElemUses) {
          if (arrElemUse.isInCatchBlock()) continue;

          //					Type useArrElemType = ((ArrayRef)arrElemUse.getValue()).getType();
          if (arrElemUse.getVar().mayEqual(varDef)) { // useArrElemType.equals(defArrElemType)) {
            // create and store array-elem DUA
            DUA arrElemDUA = new DUA(arrElemDef, arrElemUse, new Use[0], false);
            duaSet.addDUA(arrElemDUA);

            // associate DUA to array elem type
            List<DUA> duasForAE = duasPerArrElem.get(defArrElemType);
            if (duasForAE == null) {
              duasForAE = new ArrayList<DUA>();
              duasPerArrElem.put(defArrElemType, duasForAE);
            }
            duasForAE.add(arrElemDUA);

            // update count of array-elem DUAs
            ++numArrayElemDUAs;
          }
        }
      }

      // 3. Match object use/defs, simply by element type
      if (Options.includeObjDUAs()) {
        List<Def> sortedObjDefs = new ArrayList<Def>(ru.getLibObjDefs());
        Collections.sort(sortedObjDefs, new DefComparator());
        for (Def objDef : sortedObjDefs) {
          if (objDef.isInCatchBlock()) continue;

          // boolean in pair indicates whether it's instance obj (true) or class (false)
          List<Pair<RefType, Boolean>> defObjTypes = getObjTypes(objDef.getValue());
          for (Use objUse : sortedObjUses) {
            if (objUse.isInCatchBlock()) continue;

            List<Pair<RefType, Boolean>> useObjTypes = getObjTypes(objUse.getValue());
            for (Pair<RefType, Boolean> useType : useObjTypes) {
              if (defObjTypes.contains(useType)) {
                // create and store obj DUA
                DUA objDUA = new DUA(objDef, objUse, new Use[0], false);
                duaSet.addDUA(objDUA);

                // associate one DUA to each matching object type
                List<Pair<RefType, Boolean>> matchingObjTypes =
                    getMatchingTypes(defObjTypes, useObjTypes);
                for (Pair<RefType, Boolean> objType : matchingObjTypes) {
                  List<DUA> duasForObjType = duasPerObjType.get(objType);
                  if (duasForObjType == null) {
                    duasForObjType = new ArrayList<DUA>();
                    duasPerObjType.put(objType, duasForObjType);
                  }
                  duasForObjType.add(objDUA);

                  // update count of array-elem DUAs
                  ++numObjectDUAs;
                }
              }
            }
          }
        }
      }
    }

    // add possible kills to field and array-elem DUAs
    //		for (SootField fld : duasPerField.keySet()) {
    //			List<DUA> duasForField = duasPerField.get(fld);
    //			addAllOthersAsKills(duasForField);
    //		}
    //		for (Type t : duasPerArrElem.keySet()) {
    //			List<DUA> duasForAE = duasPerArrElem.get(t);
    //			addAllOthersAsKills(duasForAE);
    //		}
    // TODO: kills for obj DUAs

    System.out.println("Total field DUAs: " + numFieldDUAs);
    System.out.println("Total array elem DUAs: " + numArrayElemDUAs);
    System.out.println("Total object DUAs: " + numObjectDUAs);
  }