/** * */ package soottocfg.soot.memory_model; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.lang.model.type.NullType; import com.google.common.base.Verify; import soot.ArrayType; import soot.RefLikeType; import soot.RefType; import soot.Scene; import soot.SootClass; import soot.SootField; import soot.SootMethod; import soot.Unit; import soot.Value; import soot.jimple.ArrayRef; import soot.jimple.ClassConstant; import soot.jimple.Constant; import soot.jimple.DoubleConstant; import soot.jimple.FloatConstant; import soot.jimple.NewArrayExpr; import soot.jimple.NewMultiArrayExpr; import soot.jimple.StringConstant; import soottocfg.cfg.Program; import soottocfg.cfg.expression.Expression; import soottocfg.cfg.expression.IdentifierExpression; import soottocfg.cfg.expression.literal.NullLiteral; import soottocfg.cfg.method.Method; import soottocfg.cfg.statement.CallStatement; import soottocfg.cfg.type.BoolType; import soottocfg.cfg.type.IntType; import soottocfg.cfg.type.ReferenceType; import soottocfg.cfg.type.Type; import soottocfg.cfg.type.TypeType; import soottocfg.cfg.variable.ClassVariable; import soottocfg.cfg.variable.Variable; import soottocfg.soot.util.SootTranslationHelpers; /** * @author schaef * */ public abstract class BasicMemoryModel extends MemoryModel { protected Program program; protected final Map<soot.Type, soottocfg.cfg.type.Type> types = new HashMap<soot.Type, soottocfg.cfg.type.Type>(); protected final Map<SootField, Variable> fieldGlobals = new HashMap<SootField, Variable>(); protected final Map<Constant, Variable> constantDictionary = new HashMap<Constant, Variable>(); // protected final Type nullType; public BasicMemoryModel() { this.program = SootTranslationHelpers.v().getProgram(); } @Override public boolean isNullReference(Expression e) { return e instanceof NullLiteral; } @Override public void mkArrayWriteStatement(Unit u, ArrayRef arrayRef, Value rhs) { throw new RuntimeException("This should have been removed by the array abstraction."); } @Override public void mkArrayReadStatement(Unit u, ArrayRef arrayRef, Value lhs) { throw new RuntimeException("This should have been removed by the array abstraction."); } /* * (non-Javadoc) * * @see jayhorn.soot.memory_model.MemoryModel#mkNewArrayExpr(soot.jimple. * NewArrayExpr ) */ @Override public Expression mkNewArrayExpr(NewArrayExpr arg0) { throw new RuntimeException("This should have been removed by the array abstraction."); } /* * (non-Javadoc) * * @see * jayhorn.soot.memory_model.MemoryModel#mkNewMultiArrayExpr(soot.jimple * .NewMultiArrayExpr) */ @Override public Expression mkNewMultiArrayExpr(NewMultiArrayExpr arg0) { throw new RuntimeException("This should have been removed by the array abstraction."); } /* * (non-Javadoc) * * @see jayhorn.soot.memory_model.MemoryModel#mkStringLengthExpr(soot.Value) */ @Override public Expression mkStringLengthExpr(Value arg0) { //TODO Variable v = SootTranslationHelpers.v().getProgram().lookupGlobalVariable( "TODO" + constantDictionary.size(), IntType.instance()); return new IdentifierExpression(this.statementSwitch.getCurrentLoc(),v); } /* * (non-Javadoc) * * @see jayhorn.soot.memory_model.MemoryModel#mkNullConstant() */ @Override public Expression mkNullConstant() { return new NullLiteral(null); } /* * (non-Javadoc) * * @see jayhorn.soot.memory_model.MemoryModel#mkStringConstant(soot.jimple. * StringConstant) */ @Override public Expression mkStringConstant(StringConstant arg0) { if (!constantDictionary.containsKey(arg0)) { constantDictionary.put(arg0, SootTranslationHelpers.v().getProgram().lookupGlobalVariable( "$string" + constantDictionary.size(), lookupType(arg0.getType()))); } return new IdentifierExpression(this.statementSwitch.getCurrentLoc(), constantDictionary.get(arg0)); } /* * (non-Javadoc) * * @see jayhorn.soot.memory_model.MemoryModel#mkDoubleConstant(soot.jimple. * DoubleConstant) */ @Override public Expression mkDoubleConstant(DoubleConstant arg0) { if (!constantDictionary.containsKey(arg0)) { constantDictionary.put(arg0, SootTranslationHelpers.v().getProgram().lookupGlobalVariable( "$double" + constantDictionary.size(), lookupType(arg0.getType()))); } return new IdentifierExpression(this.statementSwitch.getCurrentLoc(), constantDictionary.get(arg0)); } /* * (non-Javadoc) * * @see jayhorn.soot.memory_model.MemoryModel#mkFloatConstant(soot.jimple. * FloatConstant) */ @Override public Expression mkFloatConstant(FloatConstant arg0) { if (!constantDictionary.containsKey(arg0)) { constantDictionary.put(arg0, SootTranslationHelpers.v().getProgram().lookupGlobalVariable( "$float" + constantDictionary.size(), lookupType(arg0.getType()))); } return new IdentifierExpression(this.statementSwitch.getCurrentLoc(), constantDictionary.get(arg0)); } // @Override // public Expression lookupClassConstant(ClassConstant arg0) { // if (!constantDictionary.containsKey(arg0)) { // constantDictionary.put(arg0, // SootTranslationHelpers.v().getProgram().lookupGlobalVariable( // "$cc" + arg0.getValue(), lookupType(arg0.getType()), true, true)); // } // return new IdentifierExpression(this.statementSwitch.getCurrentLoc(), // constantDictionary.get(arg0)); // } /* * (non-Javadoc) * * @see soottocfg.soot.memory_model.MemoryModel#lookupType(soot.Type) * TODO: check which types to use for Short, Lond, Double, and Float. */ @Override public Type lookupType(soot.Type t) { if (!types.containsKey(t)) { Type type = null; if (t instanceof soot.BooleanType) { type = BoolType.instance(); } else if (t instanceof soot.ByteType) { type = IntType.instance(); } else if (t instanceof soot.CharType) { type = IntType.instance(); } else if (t instanceof soot.DoubleType) { type = IntType.instance(); } else if (t instanceof soot.FloatType) { type = IntType.instance(); } else if (t instanceof soot.IntType) { type = IntType.instance(); } else if (t instanceof soot.LongType) { type = IntType.instance(); } else if (t instanceof soot.ShortType) { type = IntType.instance(); } else if (t instanceof RefLikeType) { type = lookupRefLikeType((RefLikeType) t); } else { throw new RuntimeException("Don't know what to do with type " + t); } types.put(t, type); } return types.get(t); } @Override public void mkConstructorCall(Unit u, SootMethod constructor, List<Expression> args) { List<Expression> receiver = new LinkedList<Expression>(); Method method = SootTranslationHelpers.v().lookupOrCreateMethod(constructor); CallStatement stmt = new CallStatement(SootTranslationHelpers.v().getSourceLocation(u), method, args, receiver); this.statementSwitch.push(stmt); } protected Type lookupRefLikeType(RefLikeType t) { if (t instanceof ArrayType) { throw new RuntimeException("Remove Arrays first. " + t); } else if (t instanceof RefType) { if ( ((RefType)t).getSootClass().equals(Scene.v().getSootClass("java.lang.Class"))) { return new TypeType(); } return new ReferenceType(lookupClassVariable(SootTranslationHelpers.v().getClassConstant(t))); } else if (t instanceof NullType) { return (ReferenceType) (new NullLiteral(null)).getType(); } throw new UnsupportedOperationException("Unsupported type " + t.getClass()); } private String classNameToSootName(String className) { return className.replace('/', '.'); } public ClassVariable lookupClassVariable(ClassConstant cc) { if (!this.constantDictionary.containsKey(cc)) { final String name = cc.getValue(); final String sootClassName = classNameToSootName(name); if (Scene.v().containsClass(sootClassName)) { SootClass c = Scene.v().getSootClass(sootClassName); Collection<ClassVariable> parents = new HashSet<ClassVariable>(); if (c.resolvingLevel() >= SootClass.HIERARCHY) { if (c.hasSuperclass()) { /** * TODO: WARNING: we had bugs before from mixing * qualified and non-qualified class * names. E.g., we had: * java.lang.Object and Object in the class hierarchy. */ SootClass superClass = c.getSuperclass(); final String bytecodeName = superClass.getType().getClassName().replace('.', '/'); parents.add(lookupClassVariable(ClassConstant.v(bytecodeName))); } else { /* * This is a hack because, for whatever reason, * Throwable and some other classes * do not have Object as their superclass. */ if (c != Scene.v().getSootClass(Object.class.getName())) { SootClass superClass = Scene.v().getSootClass(Object.class.getName()); final String bytecodeName = superClass.getType().getClassName().replace('.', '/'); parents.add(lookupClassVariable(ClassConstant.v(bytecodeName))); } } } ClassVariable cv = new ClassVariable(name, parents); this.constantDictionary.put(cc, cv); List<Variable> fields = new LinkedList<Variable>(); if (c.resolvingLevel() > SootClass.DANGLING) { for (SootField f : SootTranslationHelpers.findNonStaticFieldsRecursively(c)) { boolean isConst = SootTranslationHelpers.v().isWrittenOnce(f); fields.add(new Variable(f.getName(), this.lookupType(f.getType()), isConst, false)); } } cv.addFields(fields); } else { // System.err.println("Class not in scene: "+sootClassName); this.constantDictionary.put(cc, new ClassVariable(name, new HashSet<ClassVariable>())); } Variable v = this.constantDictionary.get(cc); Verify.verifyNotNull(v); this.program.addClassVariable((ClassVariable) v); /* * After we added the type to the dictionary, update the ref * type to avoid going into an endless loop. */ // SootClass javaLangClass = Scene.v().getSootClass("java.lang.Class"); // ReferenceType rt = lookupRefLikeType(javaLangClass.getType()); // ((ClassVariable)v).setType(rt); } return (ClassVariable) this.constantDictionary.get(cc); } }