All Downloads are FREE. Search and download functionalities are using the official Maven repository.

soot.jimple.toolkits.typing.fast.UseChecker Maven / Gradle / Ivy

There is a newer version: 2.5.0-9
Show newest version
/* Soot - a J*va Optimization Framework
 * Copyright (C) 2008 Ben Bellamy 
 * 
 * All rights reserved.
 *
 * 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.typing.fast;

import java.util.*;

import soot.*;
import soot.jimple.*;

/**
 * This checks all uses against the rules in Jimple, except some uses are not
 * checked where the bytecode verifier guarantees use validity. 
 * @author Ben Bellamy
 */
public class UseChecker extends AbstractStmtSwitch
{
	private JimpleBody jb;
	
	private Typing tg;
	private IUseVisitor uv;
	
	public UseChecker(JimpleBody jb)
	{
		this.jb = jb;
	}
	
	public void check(Typing tg, IUseVisitor uv)
	{
		try {
			this.tg = tg;	
			this.uv = uv;
			if (this.tg == null) throw new Exception("null typing passed to useChecker");
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
		
		for ( Iterator i = this.jb.getUnits().snapshotIterator();
			i.hasNext(); )
		{
			if ( uv.finish() )
				return;
			((Stmt)i.next()).apply(this);
		}
	}
	
	private void handleInvokeExpr(InvokeExpr ie, Stmt stmt)
	{
		SootMethodRef m = ie.getMethodRef();
		
		if ( ie instanceof InstanceInvokeExpr )
		{
			InstanceInvokeExpr iie = (InstanceInvokeExpr)ie;
			iie.setBase(this.uv.visit(
				iie.getBase(),m.declaringClass().getType(), stmt));
		}
		
		for ( int i = 0; i < ie.getArgCount(); i++ )
			ie.setArg(i, this.uv.visit(
				ie.getArg(i), m.parameterType(i), stmt));
	}
	
	private void handleBinopExpr(BinopExpr be, Stmt stmt, Type tlhs)
	{
		Value opl = be.getOp1(), opr = be.getOp2();
		Type tl = AugEvalFunction.eval_(this.tg, opl, stmt, this.jb),
			tr = AugEvalFunction.eval_(this.tg, opr, stmt, this.jb);
	
		if ( be instanceof AddExpr
			|| be instanceof SubExpr
			|| be instanceof MulExpr
			|| be instanceof DivExpr
			|| be instanceof RemExpr
			|| be instanceof GeExpr
			|| be instanceof GtExpr
			|| be instanceof LeExpr
			|| be instanceof LtExpr
			|| be instanceof ShlExpr
			|| be instanceof ShrExpr
			|| be instanceof UshrExpr )
		{
			if ( tlhs instanceof IntegerType )
			{
				be.setOp1(this.uv.visit(opl, IntType.v(), stmt));
				be.setOp2(this.uv.visit(opr, IntType.v(), stmt));
			}
		}
		else if ( be instanceof CmpExpr
			|| be instanceof CmpgExpr
			|| be instanceof CmplExpr )
		{
			// No checks in the original assigner
		}
		else if ( be instanceof AndExpr
			|| be instanceof OrExpr
			|| be instanceof XorExpr )
		{
			be.setOp1(this.uv.visit(opl, tlhs, stmt));
			be.setOp2(this.uv.visit(opr, tlhs, stmt));
		}
		else if ( be instanceof EqExpr
			|| be instanceof NeExpr )
		{
			if ( tl instanceof BooleanType && tr instanceof BooleanType )
			{ }
			else if ( tl instanceof Integer1Type || tr instanceof Integer1Type )
			{ }
			else if ( tl instanceof IntegerType )
			{
				be.setOp1(this.uv.visit(opl, IntType.v(), stmt));
				be.setOp2(this.uv.visit(opr, IntType.v(), stmt));
			}
		}
	}
	
	private void handleArrayRef(ArrayRef ar, Stmt stmt)
	{
		ar.setIndex(this.uv.visit(ar.getIndex(), IntType.v(), stmt));
	}
	
	private void handleInstanceFieldRef(InstanceFieldRef ifr, Stmt stmt)
	{
	    // RoboVM note: Soot used to resolve the field here but that can throw a ResolutionFailedException
	    // if e.g. the field is has been changed from static to non-static since the time of compilation.
	    // Instead we just use the declaringClass from the InstanceFieldRef similarly to what
	    // handleInvokeExpr() does.
		ifr.setBase(this.uv.visit(ifr.getBase(),
			ifr.getFieldRef().declaringClass().getType(), stmt));
	}

	public void caseBreakpointStmt(BreakpointStmt stmt) { }
	
	public void caseInvokeStmt(InvokeStmt stmt)
	{
		this.handleInvokeExpr(stmt.getInvokeExpr(), stmt);
	}
	
	public void caseAssignStmt(AssignStmt stmt)
	{
		Value lhs = stmt.getLeftOp();
		Value rhs = stmt.getRightOp();
		Type tlhs = null;
		
		
		
		if ( lhs instanceof Local )
			tlhs = this.tg.get((Local)lhs);
		else if ( lhs instanceof ArrayRef )
		{
			ArrayRef aref = (ArrayRef) lhs;
			Local base = (Local) aref.getBase();

			// Try to force Type integrity. The left side must agree on the
			// element type of the right side array reference.
			ArrayType at;
			if (this.tg.get(base) instanceof ArrayType)
				at = (ArrayType)this.tg.get(base);
			// RoboVM note: Added this else-if to fix robovm/robovm#1181
			else if (rhs.getType() instanceof PrimType)
				at = rhs.getType().makeArrayType();
			// RoboVM note: Added this else-if to fix robovm/robovm#1181
			else if (rhs instanceof Local && this.tg.get((Local) rhs) instanceof PrimType)
				at = this.tg.get((Local) rhs).makeArrayType();
			else
				at = this.tg.get(base).makeArrayType();
			tlhs = ((ArrayType)at).getElementType();

			this.handleArrayRef(aref, stmt);

			aref.setBase((Local) this.uv.visit(aref.getBase(), at, stmt));
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
			stmt.setLeftOp(this.uv.visit(lhs, tlhs, stmt));
		}
		else if ( lhs instanceof FieldRef )
		{
			tlhs = ((FieldRef)lhs).getFieldRef().type();
			if ( lhs instanceof InstanceFieldRef )
				this.handleInstanceFieldRef((InstanceFieldRef)lhs, stmt);
		}
			
		// They may have been changed above
                lhs = stmt.getLeftOp();
                rhs = stmt.getRightOp();
		
		if ( rhs instanceof Local )
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		else if ( rhs instanceof ArrayRef )
		{
			this.handleArrayRef((ArrayRef)rhs, stmt);
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		}
		else if ( rhs instanceof InstanceFieldRef )
		{
			this.handleInstanceFieldRef((InstanceFieldRef)rhs, stmt);
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		}
		else if ( rhs instanceof BinopExpr )
			this.handleBinopExpr((BinopExpr)rhs, stmt, tlhs);
		else if ( rhs instanceof InvokeExpr )
		{
			this.handleInvokeExpr((InvokeExpr)rhs, stmt);
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		}
		else if ( rhs instanceof CastExpr )
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		else if ( rhs instanceof InstanceOfExpr )
		{
			InstanceOfExpr ioe = (InstanceOfExpr)rhs;
			ioe.setOp(this.uv.visit(
				ioe.getOp(), RefType.v("java.lang.Object"), stmt));
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		}
		else if ( rhs instanceof NewArrayExpr )
		{
			NewArrayExpr nae = (NewArrayExpr)rhs;
			nae.setSize(this.uv.visit(nae.getSize(), IntType.v(), stmt));
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		}
		else if ( rhs instanceof NewMultiArrayExpr )
		{
			NewMultiArrayExpr nmae = (NewMultiArrayExpr)rhs;
			for ( int i = 0; i < nmae.getSizeCount(); i++ )
				nmae.setSize(i, this.uv.visit(
					nmae.getSize(i), IntType.v(), stmt));
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		}
		else if ( rhs instanceof LengthExpr )
		{
			stmt.setRightOp(this.uv.visit(rhs, tlhs, stmt));
		}
		else if ( rhs instanceof NegExpr )
		{
			((NegExpr)rhs).setOp(this.uv.visit(
				((NegExpr)rhs).getOp(), tlhs, stmt));
		}
	}
	
	public void caseIdentityStmt(IdentityStmt stmt) { }
	
	public void caseEnterMonitorStmt(EnterMonitorStmt stmt)
	{
		stmt.setOp(this.uv.visit(
			stmt.getOp(), RefType.v("java.lang.Object"), stmt));
	}
	
	public void caseExitMonitorStmt(ExitMonitorStmt stmt)
	{
		stmt.setOp(this.uv.visit(
			stmt.getOp(), RefType.v("java.lang.Object"), stmt));
	}
	
	public void caseGotoStmt(GotoStmt stmt) { }
	
	public void caseIfStmt(IfStmt stmt)
	{
		this.handleBinopExpr((BinopExpr)stmt.getCondition(), stmt,
			BooleanType.v());
	}
	
	public void caseLookupSwitchStmt(LookupSwitchStmt stmt)
	{
		stmt.setKey(this.uv.visit(stmt.getKey(), IntType.v(), stmt));
	}
	
	public void caseNopStmt(NopStmt stmt) { }
	
	public void caseReturnStmt(ReturnStmt stmt)
	{
		stmt.setOp(this.uv.visit(
			stmt.getOp(), this.jb.getMethod().getReturnType(), stmt));
	}
	
	public void caseReturnVoidStmt(ReturnVoidStmt stmt) { }
	
	public void caseTableSwitchStmt(TableSwitchStmt stmt)
	{
		stmt.setKey(this.uv.visit(stmt.getKey(), IntType.v(), stmt));
	}
	
	public void caseThrowStmt(ThrowStmt stmt)
	{
		stmt.setOp(this.uv.visit(
			stmt.getOp(), RefType.v("java.lang.Throwable"), stmt));
	}
	
	public void defaultCase(Stmt stmt)
	{
		throw new RuntimeException(
			"Unhandled stgtement type: " + stmt.getClass());
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy