soot.jimple.toolkits.base.ExceptionChecker Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of robovm-soot Show documentation
Show all versions of robovm-soot Show documentation
RoboVM fork of Soot - A Java optimization framework
/* Soot - a J*va Optimization Framework
* Copyright (C) 2004 Jennifer Lhotak
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package soot.jimple.toolkits.base;
import soot.*;
import soot.jimple.*;
import soot.util.*;
import java.util.*;
import soot.tagkit.*;
public class ExceptionChecker extends BodyTransformer{
FastHierarchy hierarchy;
ExceptionCheckerErrorReporter reporter;
public ExceptionChecker(ExceptionCheckerErrorReporter r){
this.reporter = r;
}
protected void internalTransform(Body b, String phaseName, Map options){
Iterator it = b.getUnits().iterator();
while (it.hasNext()){
Stmt s = (Stmt)it.next();
if (s instanceof ThrowStmt){
ThrowStmt ts = (ThrowStmt)s;
checkThrow(b, ts);
}
else if (s instanceof InvokeStmt){
InvokeStmt is = (InvokeStmt)s;
checkInvoke(b, is);
}
else if ((s instanceof AssignStmt) && (((AssignStmt)s).getRightOp() instanceof InvokeExpr)){
InvokeExpr ie = (InvokeExpr)((AssignStmt)s).getRightOp();
checkInvokeExpr(b, ie, s);
}
}
}
protected void checkThrow(Body b, ThrowStmt ts){
if (isThrowDeclared(b, ((RefType)ts.getOp().getType()).getSootClass()) || isThrowFromCompiler(ts) || isExceptionCaught(b, ts, (RefType)ts.getOp().getType())) return;
if (reporter != null){
reporter.reportError(new ExceptionCheckerError(b.getMethod(), ((RefType)ts.getOp().getType()).getSootClass(), ts, (SourceLnPosTag)ts.getOpBox().getTag("SourceLnPosTag")));
}
}
// does the method declare the throw if its a throw that needs declaring
// RuntimeException and subclasses do not need to be declared
// Error and subclasses do not need to be declared
protected boolean isThrowDeclared(Body b, SootClass throwClass){
if (hierarchy == null){
hierarchy = new FastHierarchy();
}
// handles case when exception is RuntimeException or Error
if (throwClass.equals(Scene.v().getSootClass("java.lang.RuntimeException")) || throwClass.equals(Scene.v().getSootClass("java.lang.Error"))) return true;
// handles case when exception is a subclass of RuntimeException or Error
if (hierarchy.isSubclass(throwClass, Scene.v().getSootClass("java.lang.RuntimeException")) || hierarchy.isSubclass(throwClass, Scene.v().getSootClass("java.lang.Error"))) return true;
// handles case when exact exception is thrown
if (b.getMethod().throwsException(throwClass)) return true;
// handles case when a super type of the exception is thrown
Iterator it = b.getMethod().getExceptions().iterator();
while (it.hasNext()){
SootClass nextEx = it.next();
if (hierarchy.isSubclass(throwClass, nextEx)) return true;
}
return false;
}
// is the throw created by the compiler
protected boolean isThrowFromCompiler(ThrowStmt ts){
if (ts.hasTag("ThrowCreatedByCompilerTag")) return true;
return false;
}
// is the throw caught inside the method
protected boolean isExceptionCaught(Body b, Stmt s, RefType throwType){
if (hierarchy == null){
hierarchy = new FastHierarchy();
}
Iterator it = b.getTraps().iterator();
while (it.hasNext()){
Trap trap = (Trap)it.next();
if (trap.getException().getType().equals(throwType) || hierarchy.isSubclass(throwType.getSootClass(), (trap.getException().getType()).getSootClass())){
if (isThrowInStmtRange(b, (Stmt)trap.getBeginUnit(), (Stmt)trap.getEndUnit(), s)) return true;
}
}
return false;
}
protected boolean isThrowInStmtRange(Body b, Stmt begin, Stmt end, Stmt s){
Iterator it = b.getUnits().iterator(begin, end);
while (it.hasNext()){
if (it.next().equals(s)) return true;
}
return false;
}
protected void checkInvoke(Body b, InvokeStmt is){
checkInvokeExpr(b, is.getInvokeExpr(), is);
}
// Given a method signature, see if it is declared in the given interface.
// If so, return the exceptions thrown by the declaration. Otherwise,
// Do the same thing recursively on superinterfaces and Object
// and return the intersection. This gives
// the maximal set of exceptions that could be declared to be thrown if the
// interface had declared the method. Returns null if no supertype declares
// the method.
private List getExceptionSpec(SootClass intrface,NumberedString sig) {
if(intrface.declaresMethod(sig)) return intrface.getMethod(sig).getExceptions();
List result=null;
SootClass obj=Scene.v().getSootClass("java.lang.Object");
if(obj.declaresMethod(sig)) result=new Vector(obj.getMethod(sig).getExceptions());
Iterator intrfacesit=intrface.getInterfaces().iterator();
while(intrfacesit.hasNext()) {
SootClass suprintr=(SootClass) intrfacesit.next();
List other=getExceptionSpec(suprintr,sig);
if(other!=null)
if(result==null) result=other;
else result.retainAll(other);
}
return result;
}
protected void checkInvokeExpr(Body b, InvokeExpr ie, Stmt s){
if(ie instanceof InstanceInvokeExpr &&
((InstanceInvokeExpr) ie).getBase().getType() instanceof ArrayType &&
ie.getMethodRef().name().equals("clone") &&
ie.getMethodRef().parameterTypes().size()==0)
return; // the call is to the clone() method of an array type, which
// is defined not to throw any exceptions; if we left this to
// normal resolution we'd get the method in Object which does
// throw CloneNotSupportedException
List exceptions=ie instanceof InterfaceInvokeExpr
// For an invokeinterface, there is no unique resolution for the
// method reference that will get the "correct" exception spec. We
// actually need to look at the intersection of all declarations of
// the method in supertypes.
? getExceptionSpec(ie.getMethodRef().declaringClass(),
ie.getMethodRef().getSubSignature())
// Otherwise, we just do normal resolution.
: ie.getMethod().getExceptions();
Iterator it = exceptions.iterator();
while (it.hasNext()){
SootClass sc = (SootClass)it.next();
if (isThrowDeclared(b, sc) || isExceptionCaught(b, s, sc.getType())) continue;
if (reporter != null){
if (s instanceof InvokeStmt){
reporter.reportError(new ExceptionCheckerError(b.getMethod(), sc, s, (SourceLnPosTag)s.getTag("SourceLnPosTag")));
}
else if (s instanceof AssignStmt){
reporter.reportError(new ExceptionCheckerError(b.getMethod(), sc, s, (SourceLnPosTag)((AssignStmt)s).getRightOpBox().getTag("SourceLnPosTag")));
}
}
}
}
}