/** * */ package jayhorn.utils; import java.util.HashSet; import java.util.Set; import jayhorn.Options; import jayhorn.hornify.encoder.S2H; import soottocfg.cfg.Program; import soottocfg.cfg.SourceLocation; import soottocfg.cfg.expression.BinaryExpression; import soottocfg.cfg.expression.BinaryExpression.BinaryOperator; import soottocfg.cfg.expression.Expression; import soottocfg.cfg.expression.IdentifierExpression; import soottocfg.cfg.expression.literal.IntegerLiteral; import soottocfg.cfg.method.CfgBlock; import soottocfg.cfg.method.Method; import soottocfg.cfg.statement.AssertStatement; import soottocfg.cfg.statement.AssignStatement; import soottocfg.cfg.statement.CallStatement; import soottocfg.cfg.statement.NewStatement; import soottocfg.cfg.statement.Statement; import soottocfg.cfg.type.IntType; import soottocfg.cfg.variable.Variable; /** * @author schaef * */ public class HeapCounterTransformer { public static final String outHeapCounterName = "outHeapCounter"; public HeapCounterTransformer() { } /** * Add IDs to track the calling context. There are different * strategies to do that. Currently, this only implements the * approach of assigning a unqiue number to every call statement and * passing that as extra parameter to all callees. The callee * then adds that to all pushes and pulls. * * @param p */ public void transform(Program p) { insertGlobalHeapCounter(p); } /** * Each call statement gets a unique ID. Every time we call a method, * we pass the ID of the caller as an argument. This ID is also * passed into every pull and push. * * @param p */ private void insertGlobalHeapCounter(Program p) { // start from 1 because zero is reserved for main. SourceLocation loc; for (Method m : p.getMethods()) { loc = m.getLocation(); Variable inCounter = new Variable("inHeapCounter", IntType.instance()); //IdentifierExpression inExp = new IdentifierExpression(loc, inCounter); m.getInParams().add(inCounter); m.getReturnType().add(IntType.instance()); if (m.getOutParams().isEmpty()) { throw new RuntimeException("unexpected"); } Variable outCounter = new Variable(outHeapCounterName, IntType.instance()); m.getOutParams().add(outCounter); if (m.isProgramEntryPoint()) { IdentifierExpression outExp = new IdentifierExpression(loc, outCounter); m.getSource().getStatements().add(0, new AssignStatement(m.getLocation(), outExp, new IntegerLiteral(loc, 1))); // Adding Heap Count bound checks int bound = Options.v().getHeapLimit(); if (bound > -1) { //Expression diff = new BinaryExpression(loc, BinaryExpression.BinaryOperator.Minus, outExp, inExp); Expression assrt = new BinaryExpression(loc, BinaryExpression.BinaryOperator.Le, outExp, new IntegerLiteral(loc, bound)); m.getSink().getStatements().add(0, new AssertStatement(loc, assrt)); } }else { m.getSource().getStatements().add(0, new AssignStatement(m.getLocation(), new IdentifierExpression(loc, outCounter), new IdentifierExpression(loc, inCounter))); } for (CfgBlock b : m.vertexSet()) { Set<NewStatement> newStmts = new HashSet<NewStatement>(); for (Statement s : b.getStatements()) { loc = s.getSourceLocation(); if (s instanceof CallStatement) { CallStatement cs = (CallStatement) s; cs.getArguments().add(new IdentifierExpression(loc, outCounter)); // if (cs.getCallTarget().getSource()!=null) { cs.getReceiver().add(new IdentifierExpression(loc, outCounter)); } else { cs.getReceiver().add(new IdentifierExpression(loc, new Variable("noCounter", IntType.instance()))); } //cs.getReceiver().add(new IdentifierExpression(loc, outCounter)); } else if (s instanceof NewStatement) { NewStatement ns = (NewStatement) s; ns.setCounterVar(outCounter); newStmts.add(ns); } } for (NewStatement ns : newStmts) { loc = ns.getSourceLocation(); int idx = b.getStatements().indexOf(ns); BinaryExpression plusOne = new BinaryExpression(loc, BinaryOperator.Plus, new IdentifierExpression(loc, outCounter), IntegerLiteral.one()); AssignStatement idxPlusPlus = new AssignStatement(loc, new IdentifierExpression(loc, outCounter), plusOne); b.addStatement(idx, idxPlusPlus); } } // Track of in and out bound variable counters S2H.sh().setHeapCounter(m, inCounter, outCounter); } //System.err.println(p); } }