WALA/com.ibm.wala.core/src/com/ibm/wala/cfg/exc/intra/NullPointerTransferFunction...

480 lines
18 KiB
Java

/******************************************************************************
* Copyright (c) 2002 - 2014 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*****************************************************************************/
package com.ibm.wala.cfg.exc.intra;
import com.ibm.wala.cfg.ControlFlowGraph;
import com.ibm.wala.cfg.Util;
import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.shrikeBT.IConditionalBranchInstruction;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAArrayLengthInstruction;
import com.ibm.wala.ssa.SSAArrayLoadInstruction;
import com.ibm.wala.ssa.SSAArrayStoreInstruction;
import com.ibm.wala.ssa.SSABinaryOpInstruction;
import com.ibm.wala.ssa.SSACFG;
import com.ibm.wala.ssa.SSACheckCastInstruction;
import com.ibm.wala.ssa.SSAComparisonInstruction;
import com.ibm.wala.ssa.SSAConditionalBranchInstruction;
import com.ibm.wala.ssa.SSAConversionInstruction;
import com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction;
import com.ibm.wala.ssa.SSAGetInstruction;
import com.ibm.wala.ssa.SSAGotoInstruction;
import com.ibm.wala.ssa.SSAInstanceofInstruction;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstruction.IVisitor;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.ssa.SSALoadMetadataInstruction;
import com.ibm.wala.ssa.SSAMonitorInstruction;
import com.ibm.wala.ssa.SSANewInstruction;
import com.ibm.wala.ssa.SSAPhiInstruction;
import com.ibm.wala.ssa.SSAPiInstruction;
import com.ibm.wala.ssa.SSAPutInstruction;
import com.ibm.wala.ssa.SSAReturnInstruction;
import com.ibm.wala.ssa.SSASwitchInstruction;
import com.ibm.wala.ssa.SSAThrowInstruction;
import com.ibm.wala.ssa.SSAUnaryOpInstruction;
import com.ibm.wala.ssa.SymbolTable;
import com.ibm.wala.ssa.analysis.IExplodedBasicBlock;
/**
* @author Juergen Graf <graf@kit.edu>
*
*/
class NullPointerTransferFunctionProvider<T extends ISSABasicBlock> implements ITransferFunctionProvider<T, NullPointerState> {
private final AbstractMeetOperator<NullPointerState> meet = NullPointerState.meetOperator();
private final TransferFunctionSSAVisitor visitor;
private final ControlFlowGraph<SSAInstruction, T> cfg;
NullPointerTransferFunctionProvider(ControlFlowGraph<SSAInstruction, T> cfg, IR ir) {
this.visitor = new TransferFunctionSSAVisitor(ir);
this.cfg = cfg;
}
static <T extends ISSABasicBlock> SSAInstruction getRelevantInstruction(T block) {
SSAInstruction instr = null;
if (block.getLastInstructionIndex() >= 0) {
instr = block.getLastInstruction();
}
if (instr == null && block.isCatchBlock()) {
if (block instanceof IExplodedBasicBlock) {
instr = ((IExplodedBasicBlock) block).getCatchInstruction();
} else if (block instanceof SSACFG.ExceptionHandlerBasicBlock) {
instr = ((SSACFG.ExceptionHandlerBasicBlock) block).getCatchInstruction();
} else {
throw new IllegalStateException("Unable to get catch instruction from unknown ISSABasicBlock implementation.");
}
}
return instr;
}
/* (non-Javadoc)
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#getEdgeTransferFunction(java.lang.Object, java.lang.Object)
*/
@Override
public UnaryOperator<NullPointerState> getEdgeTransferFunction(T src, T dst) {
SSAInstruction instr = getRelevantInstruction(src);
if (instr != null && cfg.hasEdge(src, dst)) {
instr.visit(visitor);
if (visitor.noIdentity) {
// do stuff
if (Util.endsWithConditionalBranch(cfg, src)) {
if (Util.getTakenSuccessor(cfg, src) == dst) {
// condition is true -> take function 1
return visitor.transfer1;
} else if (Util.getNotTakenSuccessor(cfg, src) == dst) {
// condition is true -> take function 2
return visitor.transfer2;
} else {
throw new IllegalStateException("Successor of if clause is neither true nor false case.");
}
} else {
if (cfg.getNormalSuccessors(src).contains(dst)) {
// normal case without exception -> take function 1
return visitor.transfer1;
} else if (cfg.getExceptionalSuccessors(src).contains(dst)) {
// exception has been raised -> take function 2
return visitor.transfer2;
} else {
throw new IllegalStateException("Successor not found.");
}
}
}
}
return NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#getMeetOperator()
*/
@Override
public AbstractMeetOperator<NullPointerState> getMeetOperator() {
return meet;
}
/* (non-Javadoc)
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#getNodeTransferFunction(java.lang.Object)
*/
@Override
public UnaryOperator<NullPointerState> getNodeTransferFunction(T node) {
throw new UnsupportedOperationException("We do not have such a thing dude!");
}
/* (non-Javadoc)
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#hasEdgeTransferFunctions()
*/
@Override
public boolean hasEdgeTransferFunctions() {
return true;
}
/* (non-Javadoc)
* @see com.ibm.wala.dataflow.graph.ITransferFunctionProvider#hasNodeTransferFunctions()
*/
@Override
public boolean hasNodeTransferFunctions() {
return false;
}
private static class TransferFunctionSSAVisitor implements IVisitor {
private final SymbolTable sym;
// used for true case of if clause and non-exception path
private UnaryOperator<NullPointerState> transfer1 = NullPointerState.identityFunction();
// used for false case of if clause and exceptional path
private UnaryOperator<NullPointerState> transfer2 = NullPointerState.identityFunction();
// true if sth will change. false => just use identity transfer function.
private boolean noIdentity = false;
private TransferFunctionSSAVisitor(IR ir) {
this.sym = ir.getSymbolTable();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitArrayLength(com.ibm.wala.ssa.SSAArrayLengthInstruction)
*/
@Override
public void visitArrayLength(SSAArrayLengthInstruction instruction) {
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(instruction.getArrayRef());
transfer2 = NullPointerState.nullifyFunction(instruction.getArrayRef());
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitArrayLoad(com.ibm.wala.ssa.SSAArrayLoadInstruction)
*/
@Override
public void visitArrayLoad(SSAArrayLoadInstruction instruction) {
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(instruction.getArrayRef());
transfer2 = NullPointerState.nullifyFunction(instruction.getArrayRef());
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitArrayStore(com.ibm.wala.ssa.SSAArrayStoreInstruction)
*/
@Override
public void visitArrayStore(SSAArrayStoreInstruction instruction) {
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(instruction.getArrayRef());
transfer2 = NullPointerState.nullifyFunction(instruction.getArrayRef());
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitBinaryOp(com.ibm.wala.ssa.SSABinaryOpInstruction)
*/
@Override
public void visitBinaryOp(SSABinaryOpInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitCheckCast(com.ibm.wala.ssa.SSACheckCastInstruction)
*/
@Override
public void visitCheckCast(SSACheckCastInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitComparison(com.ibm.wala.ssa.SSAComparisonInstruction)
*/
@Override
public void visitComparison(SSAComparisonInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitConditionalBranch(com.ibm.wala.ssa.SSAConditionalBranchInstruction)
*/
@Override
public void visitConditionalBranch(SSAConditionalBranchInstruction instruction) {
int arg1 = instruction.getUse(0);
int arg2 = instruction.getUse(1);
IConditionalBranchInstruction.IOperator testOp = instruction.getOperator();
if (!(testOp instanceof IConditionalBranchInstruction.Operator)) {
throw new IllegalStateException("Conditional operator of unknown type: " + testOp.getClass());
}
IConditionalBranchInstruction.Operator op = (IConditionalBranchInstruction.Operator) testOp;
if (sym.isNullConstant(arg1)) {
switch (op) {
case EQ:
noIdentity = true;
transfer1 = NullPointerState.nullifyFunction(arg2);
transfer2 = NullPointerState.denullifyFunction(arg2);
break;
case NE:
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(arg2);
transfer2 = NullPointerState.nullifyFunction(arg2);
break;
default:
throw new IllegalStateException("Comparision to a null constant using " + op);
}
} else if (sym.isNullConstant(arg2)) {
switch (op) {
case EQ:
noIdentity = true;
transfer1 = NullPointerState.nullifyFunction(arg1);
transfer2 = NullPointerState.denullifyFunction(arg1);
break;
case NE:
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(arg1);
transfer2 = NullPointerState.nullifyFunction(arg1);
break;
default:
throw new IllegalStateException("Comparision to a null constant using " + op);
}
} else {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitConversion(com.ibm.wala.ssa.SSAConversionInstruction)
*/
@Override
public void visitConversion(SSAConversionInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitGet(com.ibm.wala.ssa.SSAGetInstruction)
*/
@Override
public void visitGet(SSAGetInstruction instruction) {
if (!instruction.isStatic()) {
final int ssaVar = instruction.getRef();
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(ssaVar);
transfer2 = NullPointerState.nullifyFunction(ssaVar);
} else {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitGetCaughtException(com.ibm.wala.ssa.SSAGetCaughtExceptionInstruction)
*/
@Override
public void visitGetCaughtException(SSAGetCaughtExceptionInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitGoto(com.ibm.wala.ssa.SSAGotoInstruction)
*/
@Override
public void visitGoto(SSAGotoInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitInstanceof(com.ibm.wala.ssa.SSAInstanceofInstruction)
*/
@Override
public void visitInstanceof(SSAInstanceofInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitInvoke(com.ibm.wala.ssa.SSAInvokeInstruction)
*/
@Override
public void visitInvoke(SSAInvokeInstruction instruction) {
if (!instruction.isStatic()) {
// when no exception is raised on a virtual call, the receiver is not null. Otherwise it is
// unsure if the receiver is definitely null as an exception may also stem from the method itself.
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(instruction.getReceiver());
transfer2 = NullPointerState.identityFunction();
} else {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitLoadMetadata(com.ibm.wala.ssa.SSALoadMetadataInstruction)
*/
@Override
public void visitLoadMetadata(SSALoadMetadataInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitMonitor(com.ibm.wala.ssa.SSAMonitorInstruction)
*/
@Override
public void visitMonitor(SSAMonitorInstruction instruction) {
// when no exception is raised on a synchronized statement, the monitor is not null. Otherwise it is
// unsure if the monitor is definitely null as other exception may also appear (synchronization related).
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(instruction.getRef());
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitNew(com.ibm.wala.ssa.SSANewInstruction)
*/
@Override
public void visitNew(SSANewInstruction instruction) {
/*
* If an exception is raised upon new is called, then the defined variable
* is null else it is guaranteed to not be null.
*/
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(instruction.getDef());
transfer2 = NullPointerState.nullifyFunction(instruction.getDef());
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitPhi(com.ibm.wala.ssa.SSAPhiInstruction)
*/
@Override
public void visitPhi(SSAPhiInstruction instruction) {
noIdentity = true;
int[] uses = new int[instruction.getNumberOfUses()];
for (int i = 0; i < uses.length; i++) {
uses[i] = instruction.getUse(i);
}
transfer1 = NullPointerState.phiValueMeetFunction(instruction.getDef(), uses);
// should not be used as no alternative path exists
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitPi(com.ibm.wala.ssa.SSAPiInstruction)
*/
@Override
public void visitPi(SSAPiInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitPut(com.ibm.wala.ssa.SSAPutInstruction)
*/
@Override
public void visitPut(SSAPutInstruction instruction) {
if (!instruction.isStatic()) {
final int ssaVar = instruction.getRef();
noIdentity = true;
transfer1 = NullPointerState.denullifyFunction(ssaVar);
transfer2 = NullPointerState.nullifyFunction(ssaVar);
} else {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitReturn(com.ibm.wala.ssa.SSAReturnInstruction)
*/
@Override
public void visitReturn(SSAReturnInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitSwitch(com.ibm.wala.ssa.SSASwitchInstruction)
*/
@Override
public void visitSwitch(SSASwitchInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitThrow(com.ibm.wala.ssa.SSAThrowInstruction)
*/
@Override
public void visitThrow(SSAThrowInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
/* (non-Javadoc)
* @see com.ibm.wala.ssa.SSAInstruction.IVisitor#visitUnaryOp(com.ibm.wala.ssa.SSAUnaryOpInstruction)
*/
@Override
public void visitUnaryOp(SSAUnaryOpInstruction instruction) {
noIdentity = false;
transfer1 = NullPointerState.identityFunction();
transfer2 = NullPointerState.identityFunction();
}
}
}