/**
*
*/
package org.joogie.errormodel;
import java.util.LinkedList;
import java.util.List;
import org.joogie.GlobalsCache;
import org.joogie.soot.SootPrelude;
import org.joogie.soot.SootProcedureInfo;
import org.joogie.soot.SootStmtSwitch;
import org.joogie.util.TranslationHelpers;
import soot.Scene;
import soot.SootClass;
import soot.Trap;
import soot.jimple.Stmt;
import boogie.ProgramFactory;
import boogie.ast.Attribute;
import boogie.ast.expression.Expression;
import boogie.ast.statement.Statement;
import boogie.enums.BinaryOperator;
/**
* @author schaef
*
*/
public abstract class AbstractErrorModel {
protected SootProcedureInfo procInfo;
protected SootStmtSwitch stmtSwitch;
protected ProgramFactory pf;
public AbstractErrorModel(SootProcedureInfo pinfo, SootStmtSwitch stmtswitch) {
this.procInfo = pinfo;
this.pf = GlobalsCache.v().getPf();
this.stmtSwitch = stmtswitch;
}
/**
* Called if an exception is thrown that also occurs in the throws clause
*
* @param guard
* the condition which must be violated in order to have the
* exception thrown. May be null if the exception is always
* thrown.
* @param exception
*/
abstract public void createdExpectedException(Expression guard,
SootClass exception);
/**
* Called if an exception is thrown that also occurs in NOT the throws
* clause
*
* @param guard
* the condition which must be violated in order to have the
* exception thrown. May be null if the exception is always
* thrown.
* @param exception
*/
abstract public void createdUnExpectedException(Expression guard,
SootClass exception);
protected void createException(Expression guard, SootClass exception) {
List<Trap> traps = new LinkedList<Trap>();
List<Trap> finally_traps = new LinkedList<Trap>(); //TODO: do we have to use them here?
TranslationHelpers.getReachableTraps(this.stmtSwitch.getCurrentStatement(), this.procInfo.getSootMethod(), traps, finally_traps);
String transferlabel = null;
for (Trap trap : traps) {
if (GlobalsCache.v().isSubTypeOrEqual(exception,
trap.getException())) {
transferlabel = GlobalsCache.v().getUnitLabel(
(Stmt) trap.getHandlerUnit());
break;
}
}
if (transferlabel == null) {
// if not, check if the exception is in the throws clause
if (GlobalsCache.v().inThrowsClause(exception, this.procInfo)) {
createdExpectedException(guard, exception);
} else {
createdUnExpectedException(guard, exception);
}
} else {
// if the exception is caught, create a goto
Statement transferStatement = this.pf
.mkGotoStatement(transferlabel);
// now assign the exception variable to make sure that the catch
// block
// is feasible when we transfer there.
Expression exception_type = GlobalsCache.v().lookupClassVariable(
exception);
Statement raise = SootPrelude.v().newObject(new Attribute[] {},
this.procInfo.getExceptionVariable(), exception_type);
// if the exception is guarded create a conditional choice,
// otherwise just throw it.
if (guard != null) {
Statement[] elsePart = {TranslationHelpers
.mkLocationAssertion(this.stmtSwitch
.getCurrentStatement()),
this.pf.mkAssertStatement(
new Attribute[] { pf.mkNoVerifyAttribute() },
pf.mkBooleanLiteral(true)), raise,
transferStatement };
Statement[] thenPart = { TranslationHelpers
.mkLocationAssertion(this.stmtSwitch
.getCurrentStatement()) };
this.stmtSwitch.addStatement(this.pf.mkIfStatement(guard,
thenPart, elsePart));
} else {
this.stmtSwitch.addStatement(raise);
this.stmtSwitch.addStatement(transferStatement);
}
}
}
public Statement createAssumeNonNull(Expression expr) {
Expression guard = this.pf
.mkBinaryExpression(this.pf.getBoolType(),
BinaryOperator.COMPNEQ, expr, SootPrelude.v()
.getNullConstant());
return this.pf.mkAssumeStatement(new Attribute[0], guard);
}
public void createUnguardedException(SootClass exception) {
createException(null, exception);
}
public void createNonNullViolationException(Expression expr) {
Expression guard = this.pf
.mkBinaryExpression(this.pf.getBoolType(),
BinaryOperator.COMPNEQ, expr, SootPrelude.v()
.getNullConstant());
// TODO: it is actually not a java.lang.RuntimeException ... but I don't
// have anything usefull to report!
createException(
guard,
Scene.v().loadClass("java.lang.RuntimeException",
SootClass.SIGNATURES));
}
public void createPreconditionViolationException(Expression expr) {
// TODO: it is actually not a java.lang.RuntimeException ... but I don't
// have anything usefull to report!
createException(
expr,
Scene.v().loadClass("java.lang.RuntimeException",
SootClass.SIGNATURES));
}
public void createPostconditionViolationException(Expression expr) {
// TODO: it is actually not a java.lang.RuntimeException ... but I don't
// have anything usefull to report!
createException(
expr,
Scene.v().loadClass("java.lang.RuntimeException",
SootClass.SIGNATURES));
}
public void createArrayBoundGuard(Expression baseExpression,
Expression indexExpression) {
Expression upperbound = this.pf.mkBinaryExpression(
this.pf.getBoolType(), BinaryOperator.COMPLT, indexExpression,
GlobalsCache.v().getArraySizeExpression(baseExpression));
Expression lowerbound = this.pf.mkBinaryExpression(
this.pf.getBoolType(), BinaryOperator.COMPGEQ, indexExpression,
this.pf.mkIntLiteral("0"));
Expression guard = this.pf.mkBinaryExpression(this.pf.getBoolType(),
BinaryOperator.LOGICAND, upperbound, lowerbound);
createException(
guard,
Scene.v().loadClass("java.lang.ArrayIndexOutOfBoundsException",
SootClass.SIGNATURES));
}
public void createNonNullGuard(Expression expr) {
Expression guard = this.pf
.mkBinaryExpression(this.pf.getBoolType(),
BinaryOperator.COMPNEQ, expr, SootPrelude.v()
.getNullConstant());
createException(
guard,
Scene.v().loadClass("java.lang.NullPointerException",
SootClass.SIGNATURES));
}
public void createDivByZeroGuard(Expression expr) {
Expression guard = this.pf.mkBinaryExpression(this.pf.getBoolType(),
BinaryOperator.COMPNEQ, expr, this.pf.mkIntLiteral("0"));
createException(
guard,
Scene.v().loadClass("java.lang.ArithmeticException",
SootClass.SIGNATURES));
}
public void createClassCastGuard(Expression subtype, Expression supertype) {
Expression guard = GlobalsCache.v().compareTypeExpressions(subtype,
supertype);
createException(
guard,
Scene.v().loadClass("java.lang.ClassCastException",
SootClass.SIGNATURES));
}
}