soot.jimple.toolkits.annotation.arraycheck.ArrayBoundsChecker 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) 2000 Feng Qian
*
* 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.
*/
/*
* Modified by the Sable Research Group and others 1997-1999.
* See the 'credits' file distributed with Soot for the complete list of
* contributors. (Soot is distributed at http://www.sable.mcgill.ca/soot)
*/
package soot.jimple.toolkits.annotation.arraycheck;
import soot.options.*;
import soot.*;
import soot.jimple.*;
import soot.util.*;
import soot.tagkit.*;
import soot.jimple.toolkits.annotation.tags.*;
import java.util.*;
import soot.options.ABCOptions;
public class ArrayBoundsChecker extends BodyTransformer
{
public ArrayBoundsChecker( Singletons.Global g ) {}
public static ArrayBoundsChecker v() { return G.v().soot_jimple_toolkits_annotation_arraycheck_ArrayBoundsChecker(); }
protected boolean takeClassField = false;
protected boolean takeFieldRef = false;
protected boolean takeArrayRef = false;
protected boolean takeCSE = false;
protected boolean takeRectArray = false;
protected boolean addColorTags = false;
protected void internalTransform(Body body, String phaseName, Map opts)
{
ABCOptions options = new ABCOptions( opts );
if (options.with_all())
{
takeClassField = true;
takeFieldRef = true;
takeArrayRef = true;
takeCSE = true;
takeRectArray = true;
}
else
{
takeClassField = options.with_classfield();
takeFieldRef = options.with_fieldref();
takeArrayRef = options.with_arrayref();
takeCSE = options.with_cse();
takeRectArray = options.with_rectarray();
}
addColorTags = options.add_color_tags();
{
SootMethod m = body.getMethod();
Date start = new Date();
if (Options.v().verbose())
{
G.v().out.println("[abc] Analyzing array bounds information for "+m.getName());
G.v().out.println("[abc] Started on "+start);
}
ArrayBoundsCheckerAnalysis analysis = null;
if (hasArrayLocals(body))
{
analysis =
new ArrayBoundsCheckerAnalysis(body,
takeClassField,
takeFieldRef,
takeArrayRef,
takeCSE,
takeRectArray);
}
SootClass counterClass = null;
SootMethod increase = null;
if (options.profiling())
{
counterClass = Scene.v().loadClassAndSupport("MultiCounter");
increase = counterClass.getMethod("void increase(int)") ;
}
Chain units = body.getUnits();
IntContainer zero = new IntContainer(0);
Iterator unitIt = units.snapshotIterator();
/*
* RoboVM note: Added "analysis != null" here to prevent an NPE
* inside this loop if analysis == null. This fixes issue #275.
*/
while (analysis != null && unitIt.hasNext())
{
Stmt stmt = (Stmt)unitIt.next();
if (stmt.containsArrayRef())
{
ArrayRef aref = stmt.getArrayRef();
{
WeightedDirectedSparseGraph vgraph =
(WeightedDirectedSparseGraph)analysis.getFlowBefore(stmt);
int res = interpretGraph(vgraph, aref, stmt, zero);
boolean lowercheck = true;
boolean uppercheck = true;
if (res == 0) {
lowercheck = true;
uppercheck = true;
}
else if (res == 1) {
lowercheck = true;
uppercheck = false;
}
else if (res == 2) {
lowercheck = false;
uppercheck = true;
}
else if (res == 3) {
lowercheck = false;
uppercheck = false;
}
if (addColorTags){
if (res == 0) {
aref.getIndexBox().addTag(new ColorTag(255, 0, 0, false, "ArrayCheckTag"));
}
else if (res == 1) {
aref.getIndexBox().addTag(new ColorTag(255, 248, 35, false, "ArrayCheckTag"));
}
else if (res == 2) {
aref.getIndexBox().addTag(new ColorTag(255, 163, 0, false, "ArrayCheckTag"));
}
else if (res == 3) {
aref.getIndexBox().addTag(new ColorTag(45, 255, 84, false, "ArrayCheckTag"));
}
SootClass bodyClass = body.getMethod().getDeclaringClass();
Iterator keysIt = bodyClass.getTags().iterator();
boolean keysAdded = false;
while (keysIt.hasNext()){
Object next = keysIt.next();
if (next instanceof KeyTag){
if (((KeyTag)next).analysisType().equals("ArrayCheckTag")){
keysAdded = true;
}
}
}
if (!keysAdded){
bodyClass.addTag(new KeyTag(255, 0, 0, "ArrayBounds: Unsafe Lower and Unsafe Upper", "ArrayCheckTag"));
bodyClass.addTag(new KeyTag(255, 248, 35, "ArrayBounds: Unsafe Lower and Safe Upper", "ArrayCheckTag"));
bodyClass.addTag(new KeyTag(255, 163, 0, "ArrayBounds: Safe Lower and Unsafe Upper", "ArrayCheckTag"));
bodyClass.addTag(new KeyTag(45, 255, 84, "ArrayBounds: Safe Lower and Safe Upper", "ArrayCheckTag"));
}
}
/*
boolean lowercheck = true;
boolean uppercheck = true;
{
if (Options.v().debug())
{
if (!vgraph.makeShortestPathGraph())
{
G.v().out.println(stmt+" :");
G.v().out.println(vgraph);
}
}
Value base = aref.getBase();
Value index = aref.getIndex();
if (index instanceof IntConstant)
{
int indexv = ((IntConstant)index).value;
if (vgraph.hasEdge(base, zero))
{
int alength = vgraph.edgeWeight(base, zero);
if (-alength > indexv)
uppercheck = false;
}
if (indexv >= 0)
lowercheck = false;
}
else
{
if (vgraph.hasEdge(base, index))
{
int upperdistance = vgraph.edgeWeight(base, index);
if (upperdistance < 0)
uppercheck = false;
}
if (vgraph.hasEdge(index, zero))
{
int lowerdistance = vgraph.edgeWeight(index, zero);
if (lowerdistance <= 0)
lowercheck = false;
}
}
}*/
if (options.profiling())
{
int lowercounter = 0;
if (!lowercheck)
lowercounter = 1;
units.insertBefore (Jimple.v().newInvokeStmt(
Jimple.v().newStaticInvokeExpr(increase.makeRef(),
IntConstant.v(lowercounter))), stmt);
int uppercounter = 2;
if (!uppercheck)
uppercounter = 3;
units.insertBefore (Jimple.v().newInvokeStmt(
Jimple.v().newStaticInvokeExpr(increase.makeRef(),
IntConstant.v(uppercounter))), stmt) ;
/*
if (!lowercheck && !uppercheck)
{
units.insertBefore(Jimple.v().newInvokeStmt(
Jimple.v().newStaticInvokeExpr(increase,
IntConstant.v(4))), stmt);
NullCheckTag nullTag = (NullCheckTag)stmt.getTag("NullCheckTag");
if (nullTag != null && !nullTag.needCheck())
units.insertBefore(Jimple.v().newInvokeStmt(
Jimple.v().newStaticInvokeExpr(increase,
IntConstant.v(7))), stmt);
}
*/
}
else
{
Tag checkTag = new ArrayCheckTag(lowercheck, uppercheck);
stmt.addTag(checkTag);
}
}
}
}
if( addColorTags && takeRectArray ) {
RectangularArrayFinder raf = RectangularArrayFinder.v();
for( Iterator vbIt = body.getUseAndDefBoxes().iterator(); vbIt.hasNext(); ) {
final ValueBox vb = (ValueBox) vbIt.next();
Value v = vb.getValue();
if( !(v instanceof Local) ) continue;
Type t = v.getType();
if( !(t instanceof ArrayType) ) continue;
ArrayType at = (ArrayType) t;
if( at.numDimensions <= 1 ) continue;
vb.addTag( new ColorTag(
raf.isRectangular( new MethodLocal(m, (Local) v) )
? ColorTag.GREEN
: ColorTag.RED ));
}
}
Date finish = new Date();
if (Options.v().verbose())
{
long runtime = finish.getTime() - start.getTime();
G.v().out.println("[abc] ended on "+finish
+". It took "+(runtime/60000)+" min. "
+((runtime%60000)/1000)+" sec.");
}
}
}
private boolean hasArrayLocals(Body body)
{
Iterator localIt = body.getLocals().iterator();
while (localIt.hasNext())
{
Local local = (Local)localIt.next();
if (local.getType() instanceof ArrayType)
return true;
}
return false;
}
protected int interpretGraph(WeightedDirectedSparseGraph vgraph, ArrayRef aref, Stmt stmt, IntContainer zero){
boolean lowercheck = true;
boolean uppercheck = true;
{
if (Options.v().debug())
{
if (!vgraph.makeShortestPathGraph())
{
G.v().out.println(stmt+" :");
G.v().out.println(vgraph);
}
}
Value base = aref.getBase();
Value index = aref.getIndex();
if (index instanceof IntConstant)
{
int indexv = ((IntConstant)index).value;
if (vgraph.hasEdge(base, zero))
{
int alength = vgraph.edgeWeight(base, zero);
if (-alength > indexv)
uppercheck = false;
}
if (indexv >= 0)
lowercheck = false;
}
else
{
if (vgraph.hasEdge(base, index))
{
int upperdistance = vgraph.edgeWeight(base, index);
if (upperdistance < 0)
uppercheck = false;
}
if (vgraph.hasEdge(index, zero))
{
int lowerdistance = vgraph.edgeWeight(index, zero);
if (lowerdistance <= 0)
lowercheck = false;
}
}
}
if (lowercheck && uppercheck) return 0;
else if (lowercheck && !uppercheck) return 1;
else if (!lowercheck && uppercheck) return 2;
else return 3;
}
}