/** * */ package org.joogie.errormodel; import java.util.AbstractMap; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; import java.util.Map.Entry; import org.joogie.soot.SootProcedureInfo; import org.joogie.soot.SootStmtSwitch; import soot.SootClass; import soot.jimple.Stmt; import util.Log; import boogie.ast.expression.Expression; import boogie.ast.expression.IdentifierExpression; import boogie.ast.statement.IfStatement; import boogie.ast.statement.Statement; /** * @author schaef * */ public class ExceptionErrorModel extends AbstractErrorModel { /* exceptionWitnesses stores all the statements that are created when an * exception is thrown. Further, for each such statement, it stores a tuple * of the SootClass of the exception, and the Statement which throws the * exception. That is, once we know which of the Keys in this map are infeasible * we can remove them and all Statements that do not occur in any tuple are * safe. */ public HashMap<Statement, Entry<SootClass, Stmt>> exceptionWitnesses = new HashMap<Statement, Entry<SootClass, Stmt>>(); /* * safetyWitnesses is like exceptionWitnesses but for safe executions. This one * is used later to prove that a statement must throw an exception. */ public HashMap<Statement, Entry<SootClass, Stmt>> safetyWitnesses = new HashMap<Statement, Entry<SootClass, Stmt>>(); /* * also part of the hack ... */ public HashSet<IfStatement> createdIfStatements = new HashSet<IfStatement>(); public HashMap<Statement, Entry<SootClass, Stmt>> getExceptionWitnesses() { return exceptionWitnesses; } public ExceptionErrorModel(SootProcedureInfo pinfo, SootStmtSwitch stmtswitch) { super(pinfo, stmtswitch); } @Override public void createdExpectedException(Expression guard, SootClass exception) { this.createGuardedException(guard, exception, true); } @Override public void createdUnExpectedException(Expression guard, SootClass exception) { this.createGuardedException(guard, exception, false); } protected void createGuardedException(Expression guard, SootClass exception, boolean expected) { if (guard!=null) { SootStmtSwitch elsestmts = new SootStmtSwitch(this.procInfo); IdentifierExpression exceptionvar = elsestmts.createAllocatedVariable( exception.getType()); Statement transferStatement = this.pf.mkReturnStatement(); //collect the create statements LinkedList<Statement> elseblock = elsestmts.popAll(); //create the transfer command //"goto" if this exception is caught somewhere //"return" otherwise. Statement assign = this.pf.mkAssignmentStatement( this.procInfo.getExceptionVariable(), exceptionvar); elseblock.add(assign); //this one is only needed to have a statement that we can track in the then part of the exception handling. //!! use an identity statement to make sure that no execution is altered here. Statement assign_then = this.pf.mkAssignmentStatement(this.procInfo.getExceptionVariable(), this.procInfo.getExceptionVariable()); /* * add the exception to exceptionWitnesses and safetyWitnesses only if we * do not expect it (i.e., it is not caught or in the throws clause). */ if (!expected) { // elseblock.add( // GlobalsCache.v().getPf().mkAssignmentStatement( // procInfo.getExceptionalReturnFlag(), // GlobalsCache.v().getPf().mkBooleanLiteral(true)) // ); //store all statements that are created for throwing an exception //if any of those is feasible, then the exception might be thrown. for (Statement st : elseblock) { exceptionWitnesses.put(st, new AbstractMap.SimpleEntry<SootClass, Stmt>(exception, this.stmtSwitch.getCurrentStatement())); } safetyWitnesses.put(assign_then, new AbstractMap.SimpleEntry<SootClass, Stmt>(exception, this.stmtSwitch.getCurrentStatement())); } //set the flag that an exception was thrown. elseblock.add(transferStatement); Statement[] thenPart = {assign_then}; Statement[] elsePart = elseblock.toArray(new Statement[elseblock.size()]); IfStatement ifstmt = (IfStatement) this.pf.mkIfStatement(guard, thenPart, elsePart); this.createdIfStatements.add(ifstmt); this.stmtSwitch.addStatement(ifstmt); } else { Log.error("TODO: unguarded exceptions are not really implemented"); this.stmtSwitch.addStatement(this.pf.mkReturnStatement()); } } }