private void analyzeLocal(SootMethod method, Value value) { Local l = (Local) value; boolean objIsThreadLocal = tloa.isObjectThreadLocal(l, method); if (objIsThreadLocal) { G.v().out.println("[lg.tlo] LOCAL " + l.toString() + " is thread-local in method " + method); } else { G.v().out.println("[lg.tlo] LOCAL " + l.toString() + " is thread-shared in method " + method); } }
/** Prints the given <code>JimpleBody</code> to the specified <code>PrintWriter</code>. */ private void printLocalsInBody(Body body, UnitPrinter up) { // Print out local variables { Map typeToLocals = new DeterministicHashMap(body.getLocalCount() * 2 + 1, 0.7f); // Collect locals { Iterator localIt = body.getLocals().iterator(); while (localIt.hasNext()) { Local local = (Local) localIt.next(); List localList; Type t = local.getType(); if (typeToLocals.containsKey(t)) localList = (List) typeToLocals.get(t); else { localList = new ArrayList(); typeToLocals.put(t, localList); } localList.add(local); } } // Print locals { Iterator typeIt = typeToLocals.keySet().iterator(); while (typeIt.hasNext()) { Type type = (Type) typeIt.next(); List localList = (List) typeToLocals.get(type); Object[] locals = localList.toArray(); up.type(type); up.literal(" "); for (int k = 0; k < locals.length; k++) { if (k != 0) up.literal(", "); up.local((Local) locals[k]); } up.literal(";"); up.newline(); } } if (!typeToLocals.isEmpty()) { up.newline(); } } }
public void outADeclaration(ADeclaration node) { List localNameList = (List) mProductions.removeLast(); Type type = (Type) mProductions.removeLast(); Iterator it = localNameList.iterator(); List localList = new ArrayList(); while (it.hasNext()) { Local l = Jimple.v().newLocal((String) it.next(), type); mLocals.put(l.getName(), l); localList.add(l); } mProductions.addLast(localList); }
/** Flatten complex expressions within the AST */ public Node leave(Node old, Node n, NodeVisitor v) { if (n == noFlatten) { noFlatten = null; return n; } if (n instanceof Block) { List l = (List) stack.removeFirst(); return ((Block) n).statements(l); } else if (n instanceof Stmt && !(n instanceof LocalDecl)) { List l = (List) stack.getFirst(); l.add(n); return n; } else if (n instanceof Expr && !(n instanceof Lit) && !(n instanceof Special) && !(n instanceof Local)) { Expr e = (Expr) n; if (e instanceof Assign) { return n; } // create a local temp, initialized to the value of the complex // expression String name = newID(); LocalDecl def = nf.LocalDecl( e.position(), Flags.FINAL, nf.CanonicalTypeNode(e.position(), e.type()), name, e); def = def.localInstance(ts.localInstance(e.position(), Flags.FINAL, e.type(), name)); List l = (List) stack.getFirst(); l.add(def); // return the local temp instead of the complex expression Local use = nf.Local(e.position(), name); use = (Local) use.type(e.type()); use = use.localInstance(ts.localInstance(e.position(), Flags.FINAL, e.type(), name)); return use; } return n; }
/** Perform the appropriate flow operations for assignment to a local variable */ protected Map flowLocalAssign( DataFlowItem inItem, FlowGraph graph, LocalAssign a, Set succEdgeKeys) { Local l = (Local) a.left(); Map m = new HashMap(inItem.initStatus); MinMaxInitCount initCount = (MinMaxInitCount) m.get(l.localInstance()); // initcount could be null if the local is defined in the outer // class, or if we have not yet seen its declaration (i.e. the // local is used in its own initialization) if (initCount == null) { initCount = new MinMaxInitCount(InitCount.ZERO, InitCount.ZERO); } initCount = new MinMaxInitCount(initCount.getMin().increment(), initCount.getMax().increment()); m.put(l.localInstance(), initCount); return itemToMap(new DataFlowItem(m), succEdgeKeys); }
/** * Create a method conveniently. The method is added to the class "TestClass". Parameters can be * given as an (positional) array of local variables (the "identity statements", required by Soot * to map parameters to local variables, are inserted automatically) */ public SootMethod makeMethod( int modifier, String name, List<Local> params, soot.Type retType, List<Unit> bodyStmts) { SootMethod m = new SootMethod( name, params.stream().map(Local::getType).collect(toList()), retType, modifier); this.testClass.addMethod(m); Body body = Jimple.v().newBody(m); m.setActiveBody(body); // set the statements for the body.. first the identity statements, then the bodyStmts if (!m.isStatic()) { body.getLocals().add(localThis); body.getUnits() .add(Jimple.v().newIdentityStmt(localThis, Jimple.v().newThisRef(testClass.getType()))); } IntStream.range(0, params.size()) .forEach( pos -> { Local l = params.get(pos); ParameterRef pr = Jimple.v().newParameterRef(l.getType(), pos); body.getUnits().add(Jimple.v().newIdentityStmt(l, pr)); }); body.getUnits().addAll(bodyStmts); // set the locals for the body Set<Local> locals = Stream.concat( params.stream(), body.getUseAndDefBoxes() .stream() .filter(b -> b.getValue() instanceof Local) .map(b -> (Local) b.getValue())) .collect(toSet()); locals.removeAll(body.getLocals()); body.getLocals().addAll(locals); return m; }
/** Check that the local variable <code>l</code> is used correctly. */ protected void checkLocal(FlowGraph graph, Local l, DataFlowItem dfIn, DataFlowItem dfOut) throws SemanticException { if (!currCBI.localDeclarations.contains(l.localInstance())) { // it's a local variable that has not been declared within // this scope. The only way this can arise is from an // inner class that is not a member of a class (typically // a local class, or an anonymous class declared in a method, // constructor or initializer). // We need to check that it is a final local, and also // keep track of it, to ensure that it has been definitely // assigned at this point. currCBI.outerLocalsUsed.add(l.localInstance()); } else { MinMaxInitCount initCount = (MinMaxInitCount) dfIn.initStatus.get(l.localInstance()); if (initCount != null && InitCount.ZERO.equals(initCount.getMin())) { // the local variable may not have been initialized. // However, we only want to complain if the local is reachable if (l.reachable()) { throw new SemanticException( "Local variable \"" + l.name() + "\" may not have been initialized", l.position()); } } } }
private static boolean internalAggregate( StmtBody body, Map<ValueBox, Zone> boxToZone, boolean onlyStackVars) { LocalUses localUses; LocalDefs localDefs; ExceptionalUnitGraph graph; boolean hadAggregation = false; Chain<Unit> units = body.getUnits(); graph = new ExceptionalUnitGraph(body); localDefs = new SmartLocalDefs(graph, new SimpleLiveLocals(graph)); localUses = new SimpleLocalUses(graph, localDefs); List<Unit> unitList = new PseudoTopologicalOrderer<Unit>().newList(graph, false); for (Unit u : unitList) { if (!(u instanceof AssignStmt)) continue; AssignStmt s = (AssignStmt) u; Value lhs = s.getLeftOp(); if (!(lhs instanceof Local)) continue; Local lhsLocal = (Local) lhs; if (onlyStackVars && !lhsLocal.getName().startsWith("$")) continue; List<UnitValueBoxPair> lu = localUses.getUsesOf(s); if (lu.size() != 1) continue; UnitValueBoxPair usepair = lu.get(0); Unit use = usepair.unit; ValueBox useBox = usepair.valueBox; List<Unit> ld = localDefs.getDefsOfAt(lhsLocal, use); if (ld.size() != 1) continue; // Check to make sure aggregation pair in the same zone if (boxToZone.get(s.getRightOpBox()) != boxToZone.get(usepair.valueBox)) { continue; } /* we need to check the path between def and use */ /* to see if there are any intervening re-defs of RHS */ /* in fact, we should check that this path is unique. */ /* if the RHS uses only locals, then we know what to do; if RHS has a method invocation f(a, b, c) or field access, we must ban field writes, other method calls and (as usual) writes to a, b, c. */ boolean cantAggr = false; boolean propagatingInvokeExpr = false; boolean propagatingFieldRef = false; boolean propagatingArrayRef = false; ArrayList<FieldRef> fieldRefList = new ArrayList<FieldRef>(); LinkedList<Value> localsUsed = new LinkedList<Value>(); for (ValueBox vb : s.getUseBoxes()) { Value v = vb.getValue(); if (v instanceof Local) localsUsed.add(v); else if (v instanceof InvokeExpr) propagatingInvokeExpr = true; else if (v instanceof ArrayRef) propagatingArrayRef = true; else if (v instanceof FieldRef) { propagatingFieldRef = true; fieldRefList.add((FieldRef) v); } } // look for a path from s to use in graph. // only look in an extended basic block, though. List<Unit> path = graph.getExtendedBasicBlockPathBetween(s, use); if (path == null) continue; Iterator<Unit> pathIt = path.iterator(); // skip s. if (pathIt.hasNext()) pathIt.next(); while (pathIt.hasNext() && !cantAggr) { Stmt between = (Stmt) (pathIt.next()); if (between != use) { // Check for killing definitions for (ValueBox vb : between.getDefBoxes()) { Value v = vb.getValue(); if (localsUsed.contains(v)) { cantAggr = true; break; } if (propagatingInvokeExpr || propagatingFieldRef || propagatingArrayRef) { if (v instanceof FieldRef) { if (propagatingInvokeExpr) { cantAggr = true; break; } else if (propagatingFieldRef) { // Can't aggregate a field access if passing a definition of a field // with the same name, because they might be aliased for (FieldRef fieldRef : fieldRefList) { if (((FieldRef) v).getField() == fieldRef.getField()) { cantAggr = true; break; } } } } else if (v instanceof ArrayRef) { if (propagatingInvokeExpr) { // Cannot aggregate an invoke expr past an array write cantAggr = true; break; } else if (propagatingArrayRef) { // cannot aggregate an array read past a write // this is somewhat conservative // (if types differ they may not be aliased) cantAggr = true; break; } } } } // Make sure not propagating past a {enter,exit}Monitor if (propagatingInvokeExpr && between instanceof MonitorStmt) cantAggr = true; } // Check for intervening side effects due to method calls if (propagatingInvokeExpr || propagatingFieldRef || propagatingArrayRef) { for (final ValueBox box : between.getUseBoxes()) { if (between == use && box == useBox) { // Reached use point, stop looking for // side effects break; } Value v = box.getValue(); if (v instanceof InvokeExpr || (propagatingInvokeExpr && (v instanceof FieldRef || v instanceof ArrayRef))) { cantAggr = true; break; } } } } // we give up: can't aggregate. if (cantAggr) { continue; } /* assuming that the d-u chains are correct, */ /* we need not check the actual contents of ld */ Value aggregatee = s.getRightOp(); if (usepair.valueBox.canContainValue(aggregatee)) { boolean wasSimpleCopy = isSimpleCopy(usepair.unit); usepair.valueBox.setValue(aggregatee); units.remove(s); hadAggregation = true; // clean up the tags. If s was not a simple copy, the new statement should get // the tags of s. // OK, this fix was wrong. The condition should not be // "If s was not a simple copy", but rather "If usepair.unit // was a simple copy". This way, when there's a load of a constant // followed by an invoke, the invoke gets the tags. if (wasSimpleCopy) { // usepair.unit.removeAllTags(); usepair.unit.addAllTagsOf(s); } } else { /* if(Options.v().verbose()) { G.v().out.println("[debug] failed aggregation"); G.v().out.println("[debug] tried to put "+aggregatee+ " into "+usepair.stmt + ": in particular, "+usepair.valueBox); G.v().out.println("[debug] aggregatee instanceof Expr: " +(aggregatee instanceof Expr)); }*/ } } return hadAggregation; }