480 lines
18 KiB
Java
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();
|
|
}
|
|
|
|
}
|
|
|
|
}
|