/** * 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); }