Here are the examples of the java api org.apache.bcel.generic.MethodGen taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.
83 Examples
19
Source : RepeatedConditionals.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
private boolean compareCode(int first, int endOfFirstSegment, int second, int endOfSecondSegment, boolean oppositeChecks) {
if (endOfFirstSegment - first != endOfSecondSegment - second) {
return false;
}
MethodGen methodGen = null;
try {
methodGen = Global.getreplacedysisCache().getMethodreplacedysis(MethodGen.clreplaced, getMethodDescriptor());
} catch (CheckedreplacedysisException e) {
// Ignore
}
if (methodGen == null) {
// MethodGen is absent for some reason: fallback to byte-to-byte comparison
byte[] code = getCode().getCode();
for (int i = first; i < endOfFirstSegment; i++) {
if (code[i] != code[i - first + second]) {
return false;
}
}
return true;
}
InstructionHandle firstHandle = methodGen.getInstructionList().findHandle(first);
InstructionHandle secondHandle = methodGen.getInstructionList().findHandle(second);
while (true) {
if (firstHandle == null || secondHandle == null) {
return false;
}
if (firstHandle.getPosition() >= endOfFirstSegment) {
return secondHandle.getPosition() >= endOfSecondSegment;
}
if (secondHandle.getPosition() >= endOfSecondSegment) {
return firstHandle.getPosition() >= endOfFirstSegment;
}
Instruction firstInstruction = firstHandle.getInstruction();
Instruction secondInstruction = secondHandle.getInstruction();
if (firstInstruction instanceof BranchInstruction && secondInstruction instanceof BranchInstruction) {
int firstOpcode = firstInstruction.getOpcode();
int secondOpcode = secondInstruction.getOpcode();
if (firstOpcode != secondOpcode) {
return false;
}
int firstTarget = ((BranchInstruction) firstInstruction).getTarget().getPosition();
int secondTarget = ((BranchInstruction) secondInstruction).getTarget().getPosition();
if (firstTarget == second) {
if (oppositeChecks || secondTarget <= endOfSecondSegment) {
return false;
}
} else {
if (!((firstTarget >= first && firstTarget <= endOfFirstSegment && firstTarget - first == secondTarget - second) || firstTarget == secondTarget)) {
return false;
}
}
} else {
if (!firstInstruction.equals(secondInstruction)) {
return false;
}
}
firstHandle = firstHandle.getNext();
secondHandle = secondHandle.getNext();
}
}
19
Source : FindSqlInjection.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
private BugInstance generateBugInstance(JavaClreplaced javaClreplaced, MethodGen methodGen, InstructionHandle handle, StringAppendState stringAppendState, boolean isExecute) {
int priority = LOW_PRIORITY;
boolean sawSeriousTaint = false;
if (stringAppendState.getSawAppend(handle)) {
if (stringAppendState.getSawOpenQuote(handle) && stringAppendState.getSawCloseQuote(handle)) {
priority = HIGH_PRIORITY;
} else if (stringAppendState.getSawComma(handle)) {
priority = NORMAL_PRIORITY;
}
if (!stringAppendState.getSawUnsafeAppend(handle)) {
priority += 2;
} else if (stringAppendState.getSawSeriousTaint(handle)) {
priority--;
sawSeriousTaint = true;
} else if (!stringAppendState.getSawTaint(handle)) {
priority++;
}
}
String description;
if (isExecute) {
description = "SQL_NONCONSTANT_STRING_PreplacedED_TO_EXECUTE";
} else {
description = "SQL_PREPARED_STATEMENT_GENERATED_FROM_NONCONSTANT_STRING";
}
BugInstance bug = new BugInstance(this, description, priority);
bug.addClreplacedAndMethod(methodGen, javaClreplaced.getSourceFileName());
if (sawSeriousTaint) {
bug.addString("non-constant SQL string involving HTTP taint");
}
return bug;
}
19
Source : MemberUtils.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Checks if the method could be a lambda. Notice this is a best-check,
* since once compiled lambda methods are not univocally distinguishable.
*
* @param m The method to check if it's a lambda
* @return True if this could be a lambda, false otherwise
*/
public static boolean couldBeLambda(final MethodGen m) {
return m.isPrivate() && internalIsSynthetic(m);
}
19
Source : BugAccumulator.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
public void acreplacedulateBug(BugInstance bug, ClreplacedContext clreplacedContext, MethodGen methodGen, String sourceFile, Location location) {
acreplacedulateBug(bug, SourceLineAnnotation.fromVisitedInstruction(clreplacedContext, methodGen, sourceFile, location.getHandle()));
}
19
Source : XFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
public static XMethod createXMethod(MethodGen methodGen) {
String clreplacedName = methodGen.getClreplacedName();
String methodName = methodGen.getName();
String methodSig = methodGen.getSignature();
int accessFlags = methodGen.getAccessFlags();
return createXMethod(clreplacedName, methodName, methodSig, accessFlags);
}
19
Source : ValueNumberFrameModelingVisitor.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Visitor which models the effects of bytecode instructions on value numbers of
* values in the operand stack frames.
*
* @see ValueNumber
* @see ValueNumberFrame
* @see ValueNumberreplacedysis
* @author David Hovemeyer
*/
public clreplaced ValueNumberFrameModelingVisitor extends AbstractFrameModelingVisitor<ValueNumber, ValueNumberFrame> implements Debug, ValueNumberreplacedysisFeatures {
/*
* ----------------------------------------------------------------------
* Fields
* ----------------------------------------------------------------------
*/
private final MethodGen methodGen;
ValueNumberFactory factory;
private final ValueNumberCache cache;
private final LoadedFieldSet loadedFieldSet;
private final HashMap<Object, ValueNumber> constantValueMap;
private final HashMap<ValueNumber, String> stringConstantMap;
private InstructionHandle handle;
private static final ValueNumber[] EMPTY_INPUT_VALUE_LIST = new ValueNumber[0];
/*
* ----------------------------------------------------------------------
* Public interface
* ----------------------------------------------------------------------
*/
/**
* Constructor.
*
* @param methodGen
* the method being replacedyzed
* @param factory
* factory for ValueNumbers for the method
* @param cache
* cache of input/output transformations for each instruction
* @param loadedFieldSet
* fields loaded/stored by each instruction and entire method
* @param lookupFailureCallback
* callback to use to report clreplaced lookup failures
*/
public ValueNumberFrameModelingVisitor(MethodGen methodGen, ValueNumberFactory factory, ValueNumberCache cache, LoadedFieldSet loadedFieldSet, RepositoryLookupFailureCallback lookupFailureCallback) {
super(methodGen.getConstantPool());
this.methodGen = methodGen;
this.factory = factory;
this.cache = cache;
this.loadedFieldSet = loadedFieldSet;
this.constantValueMap = new HashMap<>();
this.stringConstantMap = new HashMap<>();
}
@Override
public ValueNumber getDefaultValue() {
return factory.createFreshValue();
}
/**
* Set the instruction handle of the instruction currently being visited.
* This must be called before the instruction accepts this visitor!
*/
public void setHandle(InstructionHandle handle) {
this.handle = handle;
}
/*
* ----------------------------------------------------------------------
* Instruction modeling
* ----------------------------------------------------------------------
*/
/**
* Determine whether redundant load elimination should be performed for the
* heap location referenced by the current instruction.
*
* @return true if we should do redundant load elimination for the current
* instruction, false if not
*/
private boolean doRedundantLoadElimination() {
if (!REDUNDANT_LOAD_ELIMINATION) {
return false;
}
XField xfield = loadedFieldSet.getField(handle);
if (xfield == null) {
return false;
}
// TODO: support two-slot fields
return !(xfield.getSignature().equals("D") || xfield.getSignature().equals("J"));
}
/**
* Determine whether forward subsreplacedution should be performed for the heap
* location referenced by the current instruction.
*
* @return true if we should do forward subsreplacedution for the current
* instruction, false if not
*/
private boolean doForwardSubsreplacedution() {
if (!REDUNDANT_LOAD_ELIMINATION) {
return false;
}
XField xfield = loadedFieldSet.getField(handle);
if (xfield == null) {
return false;
}
if (xfield.getSignature().equals("D") || xfield.getSignature().equals("J")) {
return false;
}
// Don't do forward subsreplacedution for fields that
// are never read.
return loadedFieldSet.isLoaded(xfield);
}
private void checkConsumedAndProducedValues(Instruction ins, ValueNumber[] consumedValueList, ValueNumber[] producedValueList) {
int numConsumed = ins.consumeStack(getCPG());
int numProduced = ins.produceStack(getCPG());
if (numConsumed == Const.UNPREDICTABLE) {
throw new InvalidBytecodeException("Unpredictable stack consumption for " + ins);
}
if (numProduced == Const.UNPREDICTABLE) {
throw new InvalidBytecodeException("Unpredictable stack production for " + ins);
}
if (consumedValueList.length != numConsumed) {
throw new IllegalStateException("Wrong number of values consumed for " + ins + ": expected " + numConsumed + ", got " + consumedValueList.length);
}
if (producedValueList.length != numProduced) {
throw new IllegalStateException("Wrong number of values produced for " + ins + ": expected " + numProduced + ", got " + producedValueList.length);
}
}
/**
* This is the default instruction modeling method.
*/
@Override
public void modelNormalInstruction(Instruction ins, int numWordsConsumed, int numWordsProduced) {
int flags = 0;
if (ins instanceof InvokeInstruction) {
flags = ValueNumber.RETURN_VALUE;
} else if (ins instanceof ArrayInstruction) {
flags = ValueNumber.ARRAY_VALUE;
} else if (ins instanceof ConstantPushInstruction) {
flags = ValueNumber.CONSTANT_VALUE;
}
// Get the input operands to this instruction.
ValueNumber[] inputValueList = popInputValues(numWordsConsumed);
// See if we have the output operands in the cache.
// If not, push default (fresh) values for the output,
// and add them to the cache.
ValueNumber[] outputValueList = getOutputValues(inputValueList, numWordsProduced, flags);
if (VERIFY_INTEGRITY) {
checkConsumedAndProducedValues(ins, inputValueList, outputValueList);
}
// Push output operands on stack.
pushOutputValues(outputValueList);
}
@Override
public void visitGETFIELD(GETFIELD obj) {
XField xfield = Hierarchy.findXField(obj, getCPG());
if (xfield != null) {
if (xfield.isVolatile()) {
getFrame().killAllLoads();
}
if (doRedundantLoadElimination()) {
loadInstanceField(xfield, obj);
return;
}
}
handleNormalInstruction(obj);
}
@Override
public void visitPUTFIELD(PUTFIELD obj) {
if (doForwardSubsreplacedution()) {
XField xfield = Hierarchy.findXField(obj, getCPG());
if (xfield != null) {
storeInstanceField(xfield, obj, false);
return;
}
}
handleNormalInstruction(obj);
}
@Override
public void visitGETSTATIC(GETSTATIC obj) {
ConstantPoolGen cpg = getCPG();
String fieldName = obj.getName(cpg);
String fieldSig = obj.getSignature(cpg);
ValueNumberFrame frame = getFrame();
if (RLE_DEBUG) {
System.out.println("GETSTATIC of " + fieldName + " : " + fieldSig);
}
// Is this an access of a Clreplaced object?
if (fieldName.startsWith("clreplaced$") && "Ljava/lang/Clreplaced;".equals(fieldSig)) {
String clreplacedName = fieldName.substring("clreplaced$".length()).replace('$', '.');
if (RLE_DEBUG) {
System.out.println("[found load of clreplaced object " + clreplacedName + "]");
}
ValueNumber value = factory.getClreplacedObjectValue(clreplacedName);
frame.pushValue(value);
return;
}
XField xfield = Hierarchy.findXField(obj, getCPG());
if (xfield != null) {
if (xfield.isVolatile()) {
getFrame().killAllLoads();
}
if (doRedundantLoadElimination()) {
loadStaticField(xfield, obj);
return;
}
}
handleNormalInstruction(obj);
}
@Override
public void visitPUTSTATIC(PUTSTATIC obj) {
if (doForwardSubsreplacedution()) {
XField xfield = Hierarchy.findXField(obj, getCPG());
if (xfield != null) {
storeStaticField(xfield, obj, false);
return;
}
}
handleNormalInstruction(obj);
}
@Override
public void visitINVOKESTATIC(INVOKESTATIC obj) {
if (REDUNDANT_LOAD_ELIMINATION) {
ConstantPoolGen cpg = getCPG();
String targetClreplacedName = obj.getClreplacedName(cpg);
String methodName = obj.getName(cpg);
String methodSig = obj.getSignature(cpg);
if (("forName".equals(methodName) && "java.lang.Clreplaced".equals(targetClreplacedName) || "clreplaced$".equals(methodName)) && "(Ljava/lang/String;)Ljava/lang/Clreplaced;".equals(methodSig)) {
// Access of a Clreplaced object
ValueNumberFrame frame = getFrame();
try {
ValueNumber arg = frame.getTopValue();
String clreplacedName = stringConstantMap.get(arg);
if (clreplacedName != null) {
frame.popValue();
if (RLE_DEBUG) {
System.out.println("[found access of clreplaced object " + clreplacedName + "]");
}
frame.pushValue(factory.getClreplacedObjectValue(clreplacedName));
return;
}
} catch (DataflowreplacedysisException e) {
throw new InvalidBytecodeException("stack underflow", methodGen, handle, e);
}
} else if (Hierarchy.isInnerClreplacedAccess(obj, cpg)) {
// Possible access of field via an inner-clreplaced access method
XField xfield = loadedFieldSet.getField(handle);
if (xfield != null) {
if (loadedFieldSet.instructionIsLoad(handle)) {
// Load via inner-clreplaced accessor
if (doRedundantLoadElimination()) {
if (xfield.isStatic()) {
loadStaticField(xfield, obj);
} else {
loadInstanceField(xfield, obj);
}
return;
}
} else {
// Store via inner-clreplaced accessor
if (doForwardSubsreplacedution()) {
// Some inner clreplaced access store methods
// return the value stored.
boolean pushValue = !methodSig.endsWith(")V");
if (xfield.isStatic()) {
storeStaticField(xfield, obj, pushValue);
} else {
storeInstanceField(xfield, obj, pushValue);
}
return;
}
}
}
}
}
handleNormalInstruction(obj);
}
private void killLoadsOfObjectsPreplaceded(INVOKEDYNAMIC ins) {
try {
int preplaceded = getNumWordsConsumed(ins);
ValueNumber[] arguments = allocateValueNumberArray(preplaceded);
getFrame().getTopStackWords(arguments);
for (ValueNumber v : arguments) {
getFrame().killAllLoadsOf(v);
}
} catch (DataflowreplacedysisException e) {
replacedysisContext.logError("Error in killLoadsOfObjectsPreplaceded", e);
}
}
private void killLoadsOfObjectsPreplaceded(InvokeInstruction ins) {
try {
XMethod called = Hierarchy2.findExactMethod(ins, methodGen.getConstantPool(), Hierarchy.ANY_METHOD);
if (called != null) {
NoSideEffectMethodsDatabase nse = Global.getreplacedysisCache().getOptionalDatabase(NoSideEffectMethodsDatabase.clreplaced);
if (nse != null && !nse.is(called.getMethodDescriptor(), MethodSideEffectStatus.SE, MethodSideEffectStatus.OBJ)) {
return;
}
}
FieldSummary fieldSummary = replacedysisContext.currentreplacedysisContext().getFieldSummary();
Set<XField> touched = fieldSummary.getFieldsWritten(called);
if (!touched.isEmpty()) {
getFrame().killLoadsOf(touched);
}
int preplaceded = getNumWordsConsumed(ins);
ValueNumber[] arguments = allocateValueNumberArray(preplaceded);
getFrame().killLoadsWithSimilarName(ins.getClreplacedName(cpg), ins.getMethodName(cpg));
getFrame().getTopStackWords(arguments);
for (ValueNumber v : arguments) {
getFrame().killAllLoadsOf(v);
}
// Too many false-positives for primitives without transitive FieldSummary replacedysis,
// so currently we simply kill any writable primitive on any method call
// TODO: implement transitive FieldSummary
getFrame().killAllLoads(true);
} catch (DataflowreplacedysisException e) {
replacedysisContext.logError("Error in killLoadsOfObjectsPreplaceded", e);
}
}
@Override
public void visitMONITORENTER(MONITORENTER obj) {
// Don't know what this sync invocation is doing.
// Kill all loads.
ValueNumber topValue = null;
try {
topValue = getFrame().getStackValue(0);
} catch (DataflowreplacedysisException e) {
replacedysisContext.logError("error handling monitor enter in value numbering", e);
}
getFrame().killAllLoadsExceptFor(topValue);
handleNormalInstruction(obj);
}
public void visitInvokeOnException(Instruction obj) {
if (!REDUNDANT_LOAD_ELIMINATION || !getFrame().hasAvailableLoads()) {
return;
}
if (obj instanceof INVOKEDYNAMIC) {
killLoadsOfObjectsPreplaceded((INVOKEDYNAMIC) obj);
return;
}
InvokeInstruction inv = (InvokeInstruction) obj;
if ((inv instanceof INVOKEINTERFACE || inv instanceof INVOKEVIRTUAL) && inv.getMethodName(cpg).toLowerCase().indexOf("lock") >= 0) {
// Don't know what this method invocation is doing.
// Kill all loads.
getFrame().killAllLoads();
return;
}
if (inv instanceof INVOKEVIRTUAL && "cast".equals(inv.getMethodName(cpg)) && "java.lang.Clreplaced".equals(inv.getClreplacedName(cpg))) {
// No-op
return;
}
if (inv instanceof INVOKESTATIC) {
String methodName = inv.getName(cpg);
if (("forName".equals(methodName) && "java.lang.Clreplaced".equals(inv.getClreplacedName(cpg)) || "clreplaced$".equals(methodName)) && "(Ljava/lang/String;)Ljava/lang/Clreplaced;".equals(inv.getSignature(cpg)) || (Hierarchy.isInnerClreplacedAccess((INVOKESTATIC) inv, cpg) && loadedFieldSet.getField(handle) != null)) {
return;
}
}
killLoadsOfObjectsPreplaceded(inv);
if (inv instanceof INVOKESTATIC) {
getFrame().killAllLoadsOf(null);
}
}
@Override
public void visitINVOKEVIRTUAL(INVOKEVIRTUAL obj) {
if ("cast".equals(obj.getMethodName(cpg)) && "java.lang.Clreplaced".equals(obj.getClreplacedName(cpg))) {
// treat as no-op
try {
ValueNumberFrame frame = getFrame();
ValueNumber resultType = frame.popValue();
frame.popValue();
frame.pushValue(resultType);
} catch (DataflowreplacedysisException e) {
replacedysisContext.logError("oops", e);
}
return;
}
handleNormalInstruction(obj);
}
@Override
public void visitACONST_NULL(ACONST_NULL obj) {
// Get the input operands to this instruction.
ValueNumber[] inputValueList = popInputValues(0);
// See if we have the output operands in the cache.
// If not, push default (fresh) values for the output,
// and add them to the cache.
ValueNumber[] outputValueList = getOutputValues(inputValueList, 1, ValueNumber.CONSTANT_VALUE);
if (VERIFY_INTEGRITY) {
checkConsumedAndProducedValues(obj, inputValueList, outputValueList);
}
// Push output operands on stack.
pushOutputValues(outputValueList);
}
@Override
public void visitLDC(LDC obj) {
Object constantValue = obj.getValue(cpg);
ValueNumber value;
if (constantValue instanceof ConstantClreplaced) {
ConstantClreplaced constantClreplaced = (ConstantClreplaced) constantValue;
String clreplacedName = constantClreplaced.getBytes(cpg.getConstantPool());
value = factory.getClreplacedObjectValue(clreplacedName);
} else if (constantValue instanceof ObjectType) {
ObjectType objectType = (ObjectType) constantValue;
String clreplacedName = objectType.getClreplacedName();
value = factory.getClreplacedObjectValue(clreplacedName);
} else {
value = constantValueMap.get(constantValue);
if (value == null) {
value = factory.createFreshValue(ValueNumber.CONSTANT_VALUE);
constantValueMap.put(constantValue, value);
// Keep track of String constants
if (constantValue instanceof String) {
stringConstantMap.put(value, (String) constantValue);
}
}
}
getFrame().pushValue(value);
}
@Override
public void visitIINC(IINC obj) {
if (obj.getIncrement() == 0) {
// A no-op.
return;
}
// IINC is a special case because its input and output are not on the
// stack.
// However, we still want to use the value number cache to ensure that
// this operation is modeled consistently. (If we do nothing, we miss
// the fact that the referenced local is modified.)
int local = obj.getIndex();
ValueNumber[] input = new ValueNumber[] { getFrame().getValue(local) };
ValueNumberCache.Entry entry = new ValueNumberCache.Entry(handle, input);
ValueNumber[] output = cache.lookupOutputValues(entry);
if (output == null) {
output = new ValueNumber[] { factory.createFreshValue() };
cache.addOutputValues(entry, output);
}
getFrame().setValue(local, output[0]);
}
@Override
public void visitCHECKCAST(CHECKCAST obj) {
// Do nothing
}
/*
* ----------------------------------------------------------------------
* Implementation
* ----------------------------------------------------------------------
*/
/**
* Pop the input values for the given instruction from the current frame.
*/
private ValueNumber[] popInputValues(int numWordsConsumed) {
ValueNumberFrame frame = getFrame();
ValueNumber[] inputValueList = allocateValueNumberArray(numWordsConsumed);
// Pop off the input operands.
try {
frame.getTopStackWords(inputValueList);
while (numWordsConsumed-- > 0) {
frame.popValue();
}
} catch (DataflowreplacedysisException e) {
throw new InvalidBytecodeException("Error getting input operands", e);
}
return inputValueList;
}
/**
* Push given output values onto the current frame.
*/
private void pushOutputValues(ValueNumber[] outputValueList) {
ValueNumberFrame frame = getFrame();
for (ValueNumber aOutputValueList : outputValueList) {
frame.pushValue(aOutputValueList);
}
}
/**
* Get output values for current instruction from the ValueNumberCache.
*/
private ValueNumber[] getOutputValues(ValueNumber[] inputValueList, int numWordsProduced) {
return getOutputValues(inputValueList, numWordsProduced, 0);
}
private ValueNumber[] getOutputValues(ValueNumber[] inputValueList, int numWordsProduced, int flags) {
ValueNumberCache.Entry entry = new ValueNumberCache.Entry(handle, inputValueList);
ValueNumber[] outputValueList = cache.lookupOutputValues(entry);
if (outputValueList == null) {
outputValueList = allocateValueNumberArray(numWordsProduced);
for (int i = 0; i < numWordsProduced; ++i) {
ValueNumber freshValue = factory.createFreshValue(flags);
outputValueList[i] = freshValue;
}
/*
if (false && RLE_DEBUG) {
System.out.println("<<cache fill for " + handle.getPosition() + ": " + vlts(inputValueList) + " ==> "
+ vlts(outputValueList) + ">>");
}
*/
cache.addOutputValues(entry, outputValueList);
}
/* else if (false && RLE_DEBUG) {
System.out.println("<<cache hit for " + handle.getPosition() + ": " + vlts(inputValueList) + " ==> "
+ vlts(outputValueList) + ">>");
} */
return outputValueList;
}
/**
* Creates a new empty array (if needed) with given size.
*
* @param size
* array size
* @return if size is zero, returns {@link #EMPTY_INPUT_VALUE_LIST}
*/
private static ValueNumber[] allocateValueNumberArray(int size) {
if (size == 0) {
return EMPTY_INPUT_VALUE_LIST;
}
return new ValueNumber[size];
}
private static String vlts(ValueNumber[] vl) {
StringBuilder buf = new StringBuilder();
for (ValueNumber aVl : vl) {
if (buf.length() > 0) {
buf.append(',');
}
buf.append(aVl.getNumber());
}
return buf.toString();
}
/**
* Load an instance field.
*
* @param instanceField
* the field
* @param obj
* the Instruction loading the field
*/
private void loadInstanceField(XField instanceField, Instruction obj) {
if (RLE_DEBUG) {
System.out.println("[loadInstanceField for field " + instanceField + " in instruction " + handle);
}
ValueNumberFrame frame = getFrame();
try {
ValueNumber reference = frame.popValue();
AvailableLoad availableLoad = new AvailableLoad(reference, instanceField);
if (RLE_DEBUG) {
System.out.println("[getfield of " + availableLoad + "]");
}
ValueNumber[] loadedValue = frame.getAvailableLoad(availableLoad);
if (loadedValue == null) {
// Get (or create) the cached result for this instruction
ValueNumber[] inputValueList = new ValueNumber[] { reference };
loadedValue = getOutputValues(inputValueList, getNumWordsProduced(obj));
// Make the load available
frame.addAvailableLoad(availableLoad, loadedValue);
if (RLE_DEBUG) {
System.out.println("[Making load available " + availableLoad + " <- " + vlts(loadedValue) + "]");
}
} else {
// Found an available load!
if (RLE_DEBUG) {
System.out.println("[Found available load " + availableLoad + " <- " + vlts(loadedValue) + "]");
}
}
pushOutputValues(loadedValue);
if (VERIFY_INTEGRITY) {
checkConsumedAndProducedValues(obj, new ValueNumber[] { reference }, loadedValue);
}
} catch (DataflowreplacedysisException e) {
throw new InvalidBytecodeException("Error loading from instance field", e);
}
}
/**
* Load a static field.
*
* @param staticField
* the field
* @param obj
* the Instruction loading the field
*/
private void loadStaticField(XField staticField, Instruction obj) {
if (RLE_DEBUG) {
System.out.println("[loadStaticField for field " + staticField + " in instruction " + handle);
}
ValueNumberFrame frame = getFrame();
AvailableLoad availableLoad = new AvailableLoad(staticField);
ValueNumber[] loadedValue = frame.getAvailableLoad(availableLoad);
if (loadedValue == null) {
// Make the load available
int numWordsProduced = getNumWordsProduced(obj);
loadedValue = getOutputValues(EMPTY_INPUT_VALUE_LIST, numWordsProduced);
frame.addAvailableLoad(availableLoad, loadedValue);
if (RLE_DEBUG) {
System.out.println("[making load of " + staticField + " available]");
}
} else {
if (RLE_DEBUG) {
System.out.println("[found available load of " + staticField + "]");
}
}
if (VERIFY_INTEGRITY) {
checkConsumedAndProducedValues(obj, EMPTY_INPUT_VALUE_LIST, loadedValue);
}
pushOutputValues(loadedValue);
}
/**
* Store an instance field.
*
* @param instanceField
* the field
* @param obj
* the instruction which stores the field
* @param pushStoredValue
* push the stored value onto the stack (because we are modeling
* an inner-clreplaced field access method)
*/
private void storeInstanceField(XField instanceField, Instruction obj, boolean pushStoredValue) {
if (RLE_DEBUG) {
System.out.println("[storeInstanceField for field " + instanceField + " in instruction " + handle);
}
ValueNumberFrame frame = getFrame();
int numWordsConsumed = getNumWordsConsumed(obj);
/*
* System.out.println("Instruction is " + handle);
* System.out.println("numWordsConsumed="+numWordsConsumed);
*/
ValueNumber[] inputValueList = popInputValues(numWordsConsumed);
ValueNumber reference = inputValueList[0];
ValueNumber[] storedValue = allocateValueNumberArray(inputValueList.length - 1);
System.arraycopy(inputValueList, 1, storedValue, 0, inputValueList.length - 1);
if (pushStoredValue) {
pushOutputValues(storedValue);
}
// Kill all previous loads of the same field,
// in case there is aliasing we don't know about
frame.killLoadsOfField(instanceField);
// Forward subsreplacedution
frame.addAvailableLoad(new AvailableLoad(reference, instanceField), storedValue);
if (RLE_DEBUG) {
System.out.println("[making store of " + instanceField + " available]");
}
if (VERIFY_INTEGRITY) {
/*
* System.out.println("pushStoredValue="+pushStoredValue);
*/
checkConsumedAndProducedValues(obj, inputValueList, pushStoredValue ? storedValue : EMPTY_INPUT_VALUE_LIST);
}
}
/**
* Store a static field.
*
* @param staticField
* the static field
* @param obj
* the instruction which stores the field
* @param pushStoredValue
* push the stored value onto the stack (because we are modeling
* an inner-clreplaced field access method)
*/
private void storeStaticField(XField staticField, Instruction obj, boolean pushStoredValue) {
if (RLE_DEBUG) {
System.out.println("[storeStaticField for field " + staticField + " in instruction " + handle);
}
ValueNumberFrame frame = getFrame();
AvailableLoad availableLoad = new AvailableLoad(staticField);
int numWordsConsumed = getNumWordsConsumed(obj);
ValueNumber[] inputValueList = popInputValues(numWordsConsumed);
if (pushStoredValue) {
pushOutputValues(inputValueList);
}
// Kill loads of this field
frame.killLoadsOfField(staticField);
// Make load available
frame.addAvailableLoad(availableLoad, inputValueList);
if (RLE_DEBUG) {
System.out.println("[making store of " + staticField + " available]");
}
if (VERIFY_INTEGRITY) {
checkConsumedAndProducedValues(obj, inputValueList, pushStoredValue ? inputValueList : EMPTY_INPUT_VALUE_LIST);
}
}
}
19
Source : ValueNumberAnalysis.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* <p>A dataflow replacedysis to track the production and flow of values in the Java
* stack frame. See the {@link ValueNumber ValueNumber} clreplaced for an explanation
* of what the value numbers mean, and when they can be compared.</p>
*
* <p>
* This clreplaced is still experimental.</p>
*
* @author David Hovemeyer
* @see ValueNumber
* @see edu.umd.cs.findbugs.ba.Dominatorsreplacedysis
*/
public clreplaced ValueNumberreplacedysis extends FrameDataflowreplacedysis<ValueNumber, ValueNumberFrame> {
private final static boolean TRACE = SystemProperties.getBoolean("vna.trace");
public static final boolean DEBUG = TRACE || SystemProperties.getBoolean("vna.debug");
private final MethodGen methodGen;
private final ValueNumberFactory factory;
private final ValueNumberFrameModelingVisitor visitor;
private final ValueNumber[] entryLocalValueList;
private final IdenreplacedyHashMap<BasicBlock, ValueNumber> exceptionHandlerValueNumberMap;
private ValueNumber thisValue;
private final HashMap<Location, ValueNumberFrame> factAtLocationMap;
private final HashMap<Location, ValueNumberFrame> factAfterLocationMap;
private MergeTree mergeTree;
public ValueNumberreplacedysis(MethodGen methodGen, DepthFirstSearch dfs, LoadedFieldSet loadedFieldSet, RepositoryLookupFailureCallback lookupFailureCallback) {
super(dfs);
this.methodGen = methodGen;
this.factory = new ValueNumberFactory();
ValueNumberCache cache = new ValueNumberCache();
this.visitor = new ValueNumberFrameModelingVisitor(methodGen, factory, cache, loadedFieldSet, lookupFailureCallback);
int numLocals = methodGen.getMaxLocals();
this.entryLocalValueList = new ValueNumber[numLocals];
for (int i = 0; i < numLocals; ++i) {
this.entryLocalValueList[i] = factory.createFreshValue();
}
this.exceptionHandlerValueNumberMap = new IdenreplacedyHashMap<>();
// For non-static methods, keep track of which value represents the
// "this" reference
if (!methodGen.isStatic()) {
this.thisValue = entryLocalValueList[0];
}
this.factAtLocationMap = new HashMap<>();
this.factAfterLocationMap = new HashMap<>();
if (DEBUG) {
System.out.println("VNA replacedysis " + methodGen.getClreplacedName() + "." + methodGen.getName() + " : " + methodGen.getSignature());
}
}
public ValueNumber getClreplacedObjectValue(String clreplacedName) {
return visitor.factory.getClreplacedObjectValue(clreplacedName);
}
public void setMergeTree(MergeTree mergeTree) {
this.mergeTree = mergeTree;
}
public MergeTree getMergeTree() {
return mergeTree;
}
public ValueNumberFactory getFactory() {
return factory;
}
public int getNumValuesAllocated() {
return factory.getNumValuesAllocated();
}
public boolean isThisValue(ValueNumber value) {
return thisValue != null && thisValue.getNumber() == value.getNumber();
}
public ValueNumber getThisValue() {
return thisValue;
}
/**
* Get the value number replacedigned to the given local variable upon entry to
* the method.
*
* @param local
* local variable number
* @return ValueNumber replacedigned to the local variable
*/
public ValueNumber getEntryValue(int local) {
return entryLocalValueList[local];
}
/**
* Get the value number replacedigned to the given parameter upon entry to the
* method.
*
* @param param
* a parameter (0 == first parameter)
* @return the ValueNumber replacedigned to that parameter
*/
public ValueNumber getEntryValueForParameter(int param) {
SignatureParser sigParser = new SignatureParser(methodGen.getSignature());
int p = 0;
int slotOffset = methodGen.isStatic() ? 0 : 1;
for (String paramSig : sigParser.parameterSignatures()) {
if (p == param) {
return getEntryValue(slotOffset);
}
p++;
slotOffset += SignatureParser.getNumSlotsForType(paramSig);
}
throw new IllegalStateException();
}
@Override
public ValueNumberFrame createFact() {
return new ValueNumberFrame(methodGen.getMaxLocals());
}
@Override
public void initEntryFact(ValueNumberFrame result) {
// Change the frame from TOP to something valid.
result.setValid();
// At entry to the method, each local has (as far as we know) a unique
// value.
int numSlots = result.getNumSlots();
for (int i = 0; i < numSlots; ++i) {
result.setValue(i, entryLocalValueList[i]);
}
}
@Override
public void transfer(BasicBlock basicBlock, InstructionHandle end, ValueNumberFrame start, ValueNumberFrame result) throws DataflowreplacedysisException {
if (basicBlock.isExceptionThrower() && isFactValid(start)) {
/* If exceptionThrower is invoke instruction then it's possible that
* it was partially executed before an exception occurred
* So we have to kill available loads when control is transferred to the catch block
*/
InstructionHandle handle = basicBlock.getExceptionThrower();
Instruction inst = handle.getInstruction();
if (inst instanceof InvokeInstruction) {
copy(start, result);
visitor.setFrameAndLocation(result, new Location(handle, basicBlock));
visitor.setHandle(handle);
visitor.visitInvokeOnException(inst);
return;
}
}
super.transfer(basicBlock, end, start, result);
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, ValueNumberFrame fact) throws DataflowreplacedysisException {
Location location = new Location(handle, basicBlock);
ValueNumberFrame atLocation = getFactAtLocation(location);
copy(fact, atLocation);
visitor.setFrameAndLocation(fact, location);
visitor.setHandle(handle);
visitor.replacedyzeInstruction(handle.getInstruction());
ValueNumberFrame afterLocation = getFactAfterLocation(location);
copy(fact, afterLocation);
}
@Override
public void meetInto(ValueNumberFrame fact, Edge edge, ValueNumberFrame result) throws DataflowreplacedysisException {
if (edge.getTarget().isExceptionHandler() && fact.isValid()) {
// Special case: when merging predecessor facts for entry to
// an exception handler, we clear the stack and push a
// single entry for the exception object. That way, the locals
// can still be merged.
// Get the value number for the exception
BasicBlock handlerBlock = edge.getTarget();
ValueNumber exceptionValueNumber = getExceptionValueNumber(handlerBlock);
// Set up the stack frame
ValueNumberFrame tmpFact = createFact();
tmpFact.copyFrom(fact);
tmpFact.clearStack();
tmpFact.pushValue(exceptionValueNumber);
fact = tmpFact;
}
mergeInto(fact, result);
}
@Override
protected void mergeInto(ValueNumberFrame frame, ValueNumberFrame result) throws DataflowreplacedysisException {
result.mergeAvailableLoadSets(frame, factory, mergeTree);
super.mergeInto(frame, result);
}
@Override
protected void mergeValues(ValueNumberFrame otherFrame, ValueNumberFrame resultFrame, int slot) throws DataflowreplacedysisException {
ValueNumber value = mergeValues(resultFrame, slot, resultFrame.getValue(slot), otherFrame.getValue(slot));
resultFrame.setValue(slot, value);
}
private ValueNumber mergeValues(ValueNumberFrame frame, int slot, ValueNumber mine, ValueNumber other) {
// Merging slot values:
// - Merging identical values results in no change
// - If the values are different, and the value in the result
// frame is not the result of a previous result, a fresh value
// is allocated.
// - If the value in the result frame is the result of a
// previous merge, IT STAYS THE SAME.
//
// The "one merge" rule means that merged values are essentially like
// phi nodes. They combine some number of other values.
// I believe (but haven't proved) that this technique is a dumb way
// of computing SSA.
if (mine != frame.getValue(slot)) {
throw new IllegalStateException();
}
if (mine.equals(other)) {
return mine;
}
ValueNumber mergedValue = frame.getMergedValue(slot);
if (mergedValue == null) {
mergedValue = factory.createFreshValue(ValueNumber.mergeFlags(mine.getFlags(), other.getFlags()) | ValueNumber.PHI_NODE);
frame.setMergedValue(slot, mergedValue);
}
if (mergeTree != null) {
mergeTree.mapInputToOutput(mine, mergedValue);
mergeTree.mapInputToOutput(other, mergedValue);
}
return mergedValue;
}
@Override
public ValueNumberFrame getFactAtLocation(Location location) {
ValueNumberFrame fact = factAtLocationMap.get(location);
if (fact == null) {
fact = createFact();
makeFactTop(fact);
factAtLocationMap.put(location, fact);
}
return fact;
}
@Override
public ValueNumberFrame getFactAfterLocation(Location location) {
if (TRACE) {
System.out.println("getting fact after " + location);
}
ValueNumberFrame fact = factAfterLocationMap.get(location);
if (fact == null) {
if (TRACE) {
System.out.println("Initialized fact after " + location + " @ " + Integer.toHexString(System.idenreplacedyHashCode(location)) + " in " + Integer.toHexString(System.idenreplacedyHashCode(this)) + " : " + factAfterLocationMap.containsKey(location));
}
fact = createFact();
makeFactTop(fact);
factAfterLocationMap.put(location, fact);
}
return fact;
}
/**
* Get an Iterator over all dataflow facts that we've recorded for the
* Locations in the CFG. Note that this does not include result facts (since
* there are no Locations corresponding to the end of basic blocks).
*/
public Iterator<ValueNumberFrame> facreplacederator() {
return factAtLocationMap.values().iterator();
}
// These fields are used by the compactValueNumbers() method.
/*
private static clreplaced ValueCompacter {
public final BitSet valuesUsed;
public int numValuesUsed;
public final int[] discovered;
public ValueCompacter(int origNumValuesAllocated) {
valuesUsed = new BitSet();
numValuesUsed = 0;
// The "discovered" array tells us the mapping of old value numbers
// to new (which are based on order of discovery). Negative values
// specify value numbers which are not actually used (and thus can
// be purged.)
discovered = new int[origNumValuesAllocated];
for (int i = 0; i < discovered.length; ++i) {
discovered[i] = -1;
}
}
public boolean isUsed(int number) {
return valuesUsed.get(number);
}
public void setUsed(int number) {
valuesUsed.set(number, true);
}
public int allocateValue() {
return numValuesUsed++;
}
}
*/
/**
* <p>Compact the value numbers replacedigned. This should be done only after the
* dataflow algorithm has executed. This works by modifying the actual
* ValueNumber objects replacedigned. After this method is called, the
* getNumValuesAllocated() method of this object will return a value less
* than or equal to the value it would have returned before the call to this
* method.
* </p>
* <p>
* <em>This method should be called at most once</em>.
* </p>
* @param dataflow
* the Dataflow object which executed this replacedysis (and has all
* of the block result values)
*/
@Deprecated
public void compactValueNumbers(Dataflow<ValueNumberFrame, ValueNumberreplacedysis> dataflow) {
throw new UnsupportedOperationException();
}
/**
* Mark value numbers in a value number frame for compaction.
*
* private static void markFrameValues(ValueNumberFrame frame, ValueCompacter compacter) {
* // We don't need to do anything for top and bottom frames.
* if (!frame.isValid()) {
* return;
* }
*
* for (int j = 0; j < frame.getNumSlots(); ++j) {
* ValueNumber value = frame.getValue(j);
* int number = value.getNumber();
*
* if (!compacter.isUsed(number)) {
* compacter.discovered[number] = compacter.allocateValue();
* compacter.setUsed(number);
* }
* }
* }
*/
// /**
// * Test driver.
// */
// public static void main(String[] argv) throws Exception {
//
// if (argv.length != 1) {
// System.out.println("Usage: edu.umd.cs.findbugs.ba.ValueNumberreplacedysis <filename>");
// System.exit(1);
// }
//
// DataflowTestDriver<ValueNumberFrame, ValueNumberreplacedysis> driver =
// new DataflowTestDriver<ValueNumberFrame, ValueNumberreplacedysis>() {
// @Override
// public Dataflow<ValueNumberFrame, ValueNumberreplacedysis>
// createDataflow(ClreplacedContext clreplacedContext, Method method)
// throws CFGBuilderException, DataflowreplacedysisException {
// return clreplacedContext.getValueNumberDataflow(method);
// }
// };
//
// driver.execute(argv[0]);
// }
private ValueNumber getExceptionValueNumber(BasicBlock handlerBlock) {
ValueNumber valueNumber = exceptionHandlerValueNumberMap.get(handlerBlock);
if (valueNumber == null) {
valueNumber = factory.createFreshValue();
exceptionHandlerValueNumberMap.put(handlerBlock, valueNumber);
}
return valueNumber;
}
@CheckForNull
@DottedClreplacedName
public String getClreplacedName(ValueNumber v) {
return factory.getClreplacedName(v);
}
}
19
Source : SignatureConverter.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Convenience method for generating a method signature in human readable
* form.
*
* @param methodGen
* the method to produce a method signature for
*/
public static String convertMethodSignature(MethodGen methodGen) {
return convertMethodSignature(methodGen.getClreplacedName(), methodGen.getName(), methodGen.getSignature());
}
19
Source : ResourceValueAnalysis.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
@javax.annotation.ParametersAreNonnullByDefault
public clreplaced ResourceValuereplacedysis<Resource> extends FrameDataflowreplacedysis<ResourceValue, ResourceValueFrame> implements EdgeTypes {
private static final boolean DEBUG = SystemProperties.getBoolean("dataflow.debug");
private final MethodGen methodGen;
private final CFG cfg;
private final ResourceTracker<Resource> resourceTracker;
private final Resource resource;
private final ResourceValueFrameModelingVisitor visitor;
private final boolean ignoreImplicitExceptions;
public ResourceValuereplacedysis(MethodGen methodGen, CFG cfg, DepthFirstSearch dfs, ResourceTracker<Resource> resourceTracker, Resource resource) {
super(dfs);
this.methodGen = methodGen;
this.cfg = cfg;
this.resourceTracker = resourceTracker;
this.resource = resource;
this.visitor = resourceTracker.createVisitor(resource, methodGen.getConstantPool());
this.ignoreImplicitExceptions = resourceTracker.ignoreImplicitExceptions(resource);
}
@Override
public ResourceValueFrame createFact() {
ResourceValueFrame fact = new ResourceValueFrame(methodGen.getMaxLocals());
fact.setTop();
return fact;
}
@Override
public void initEntryFact(ResourceValueFrame result) {
result.setValid();
result.clearStack();
final int numSlots = result.getNumSlots();
for (int i = 0; i < numSlots; ++i) {
boolean slotContainsInstance = resourceTracker.isParamInstance(resource, i);
result.setValue(i, slotContainsInstance ? ResourceValue.instance() : ResourceValue.notInstance());
}
}
@Override
public void meetInto(ResourceValueFrame fact, Edge edge, ResourceValueFrame result) throws DataflowreplacedysisException {
BasicBlock source = edge.getSource();
BasicBlock dest = edge.getTarget();
ResourceValueFrame tmpFact = null;
if (edge.isExceptionEdge()) {
// If this edge throws only implicit exceptions
// (as determined by Typereplacedysis and
// PruneInfeasibleExceptionEdges),
// and the resource tracker says to ignore implicit exceptions
// for this resource, ignore it.
if (replacedysisContext.currentreplacedysisContext().getBoolProperty(replacedysisFeatures.ACCURATE_EXCEPTIONS) && ignoreImplicitExceptions && !edge.isFlagSet(EXPLICIT_EXCEPTIONS_FLAG)) {
return;
}
// The ResourceTracker may veto the exception edge
if (resourceTracker.ignoreExceptionEdge(edge, resource, methodGen.getConstantPool())) {
return;
}
if (fact.getStatus() == ResourceValueFrame.OPEN) {
// If status is OPEN, downgrade to OPEN_ON_EXCEPTION_PATH
tmpFact = modifyFrame(fact, null);
tmpFact.setStatus(ResourceValueFrame.OPEN_ON_EXCEPTION_PATH);
}
if (fact.isValid()) {
// Special case: if the instruction that closes the resource
// throws an exception, we consider the resource to be
// successfully
// closed anyway.
InstructionHandle exceptionThrower = source.getExceptionThrower();
BasicBlock fallThroughSuccessor = cfg.getSuccessorWithEdgeType(source, FALL_THROUGH_EDGE);
if (DEBUG && fallThroughSuccessor == null) {
System.out.println("Null fall through successor!");
}
if (fallThroughSuccessor != null && resourceTracker.isResourceClose(fallThroughSuccessor, exceptionThrower, methodGen.getConstantPool(), resource, fact)) {
tmpFact = modifyFrame(fact, tmpFact);
tmpFact.setStatus(ResourceValueFrame.CLOSED);
if (DEBUG) {
System.out.print("(failed attempt to close)");
}
}
}
if (dest.isExceptionHandler()) {
// Clear stack, push value for exception
if (fact.isValid()) {
tmpFact = modifyFrame(fact, tmpFact);
tmpFact.clearStack();
tmpFact.pushValue(ResourceValue.notInstance());
}
}
}
// Make the resource nonexistent if it is compared against null
int edgeType = edge.getType();
if (edgeType == IFCMP_EDGE || edgeType == FALL_THROUGH_EDGE) {
InstructionHandle lastInSourceHandle = source.getLastInstruction();
if (lastInSourceHandle != null) {
Instruction lastInSource = lastInSourceHandle.getInstruction();
boolean isNullCheck = false;
boolean isNonNullCheck = false;
// This check catches null == X, null != X
if (lastInSource instanceof IF_ACMPEQ || lastInSource instanceof IF_ACMPNE) {
Location l = new Location(lastInSourceHandle, source);
InstructionHandle ih = l.getHandle();
// Get instruction that pushed topmost
InstructionHandle ihPrev = ih.getPrev();
// Get next-topmost that pushed next-topmost
InstructionHandle ihPrevPrev = ihPrev == null ? null : ihPrev.getPrev();
int prevPush = 0;
if (ihPrev != null) {
prevPush = ihPrev.getInstruction().produceStack(methodGen.getConstantPool());
}
int prevPrevPush = 0;
if (ihPrevPrev != null) {
prevPrevPush = ihPrevPrev.getInstruction().produceStack(methodGen.getConstantPool());
}
// If instructions exist and both push one word onto the
// stack and the next-topmost pushes null...
if (ihPrev != null && ihPrevPrev != null && prevPush == 1 && prevPrevPush == 1 && ihPrevPrev.getInstruction().getOpcode() == Const.ACONST_NULL) {
// Topmost item on stack is being compared with null
// (the null itself is next-topmost on the stack)
isNullCheck = lastInSource instanceof IF_ACMPEQ;
isNonNullCheck = lastInSource instanceof IF_ACMPNE;
}
} else // This check catches X == null, X != null
if (lastInSource instanceof IFNULL || lastInSource instanceof IFNONNULL) {
isNullCheck = lastInSource instanceof IFNULL;
isNonNullCheck = lastInSource instanceof IFNONNULL;
}
if (isNullCheck || isNonNullCheck) {
// Get the frame at the if statement
ResourceValueFrame startFrame = getStartFact(source);
if (startFrame.isValid()) {
// The source block has a valid start fact.
// That means it is safe to inspect the frame at the If
// instruction.
ResourceValueFrame frameAtIf = getFactAtLocation(new Location(lastInSourceHandle, source));
ResourceValue topValue = frameAtIf.getValue(frameAtIf.getNumSlots() - 1);
if (topValue.isInstance()) {
if ((isNullCheck && edgeType == IFCMP_EDGE) || (isNonNullCheck && edgeType == FALL_THROUGH_EDGE)) {
// System.out.println("**** making resource nonexistent on edge "+edge.getId());
tmpFact = modifyFrame(fact, tmpFact);
tmpFact.setStatus(ResourceValueFrame.NONEXISTENT);
}
}
}
}
}
}
if (tmpFact != null) {
fact = tmpFact;
}
mergeInto(fact, result);
}
@Override
protected void mergeInto(ResourceValueFrame frame, ResourceValueFrame result) throws DataflowreplacedysisException {
// Merge slots
super.mergeInto(frame, result);
// Merge status
result.setStatus(Math.min(result.getStatus(), frame.getStatus()));
}
@Override
protected void mergeValues(ResourceValueFrame otherFrame, ResourceValueFrame resultFrame, int slot) throws DataflowreplacedysisException {
ResourceValue value = ResourceValue.merge(resultFrame.getValue(slot), otherFrame.getValue(slot));
resultFrame.setValue(slot, value);
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, ResourceValueFrame fact) throws DataflowreplacedysisException {
visitor.setFrameAndLocation(fact, new Location(handle, basicBlock));
visitor.transferInstruction(handle, basicBlock);
}
}
19
Source : PruneUnconditionalExceptionThrowerEdges.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
public clreplaced PruneUnconditionalExceptionThrowerEdges implements EdgeTypes {
private static final boolean DEBUG = SystemProperties.getBoolean("cfg.prune.throwers.debug");
private static final boolean DEBUG_DIFFERENCES = SystemProperties.getBoolean("cfg.prune.throwers.differences.debug");
private static final String UNCONDITIONAL_THROWER_METHOD_NAMES = SystemProperties.getProperty("findbugs.unconditionalThrower", " ").replace(',', '|');
private final MethodGen methodGen;
private final CFG cfg;
private final ConstantPoolGen cpg;
private final TypeDataflow typeDataflow;
private final replacedysisContext replacedysisContext;
private boolean cfgModified;
private static final Pattern unconditionalThrowerPattern;
private static final BitSet RETURN_OPCODE_SET = new BitSet();
static {
RETURN_OPCODE_SET.set(Const.ARETURN);
RETURN_OPCODE_SET.set(Const.IRETURN);
RETURN_OPCODE_SET.set(Const.LRETURN);
RETURN_OPCODE_SET.set(Const.DRETURN);
RETURN_OPCODE_SET.set(Const.FRETURN);
RETURN_OPCODE_SET.set(Const.RETURN);
Pattern p;
try {
p = Pattern.compile(UNCONDITIONAL_THROWER_METHOD_NAMES);
if (DEBUG) {
System.out.println("Pattern is '" + p + "'");
System.out.println(p.matcher("showInvalidPage").matches());
}
} catch (RuntimeException e) {
replacedysisContext.logError("Error compiling unconditional thrower pattern " + UNCONDITIONAL_THROWER_METHOD_NAMES, e);
p = Pattern.compile(" ");
}
unconditionalThrowerPattern = p;
}
public PruneUnconditionalExceptionThrowerEdges(/* ClreplacedContext clreplacedContext, */
JavaClreplaced javaClreplaced, Method method, MethodGen methodGen, CFG cfg, ConstantPoolGen cpg, TypeDataflow typeDataflow, replacedysisContext replacedysisContext) {
// this.clreplacedContext = clreplacedContext;
this.methodGen = methodGen;
this.cfg = cfg;
this.cpg = cpg;
this.typeDataflow = typeDataflow;
this.replacedysisContext = replacedysisContext;
}
public void execute() throws DataflowreplacedysisException {
replacedysisContext currentreplacedysisContext = replacedysisContext.currentreplacedysisContext();
if (currentreplacedysisContext.getBoolProperty(replacedysisFeatures.CONSERVE_SPACE)) {
throw new IllegalStateException("This should not happen");
}
boolean foundInexact = false;
Set<Edge> deletedEdgeSet = new HashSet<>();
// TypeDataflow typeDataflow = clreplacedContext.getTypeDataflow(method);
if (DEBUG) {
System.out.println("PruneUnconditionalExceptionThrowerEdges: examining " + SignatureConverter.convertMethodSignature(methodGen));
}
for (Iterator<BasicBlock> i = cfg.blockIterator(); i.hasNext(); ) {
BasicBlock basicBlock = i.next();
if (!basicBlock.isExceptionThrower()) {
continue;
}
InstructionHandle instructionHandle = basicBlock.getExceptionThrower();
Instruction exceptionThrower = instructionHandle.getInstruction();
if (!(exceptionThrower instanceof InvokeInstruction)) {
continue;
}
if (exceptionThrower instanceof INVOKEDYNAMIC) {
continue;
}
InvokeInstruction inv = (InvokeInstruction) exceptionThrower;
boolean foundThrower = false;
boolean foundNonThrower = false;
boolean isExact = true;
XMethod primaryXMethod = XFactory.createXMethod(inv, cpg);
final String methodName = primaryXMethod.getName();
final boolean matches = unconditionalThrowerPattern.matcher(methodName).matches();
if (DEBUG) {
System.out.println("Checking '" + methodName + "' is " + matches);
}
if (matches) {
if (DEBUG) {
System.out.println("\tmatched for " + instructionHandle + " : " + primaryXMethod);
}
foundThrower = true;
} else if (inv instanceof INVOKEINTERFACE) {
continue;
} else if (inv instanceof INVOKESTATIC) {
foundThrower = isUnconditionalThrower(primaryXMethod);
} else {
String clreplacedName = inv.getClreplacedName(cpg);
if (DEBUG) {
System.out.println("\tlooking up method for " + instructionHandle + " : " + primaryXMethod);
}
Location loc = new Location(instructionHandle, basicBlock);
TypeFrame typeFrame = typeDataflow.getFactAtLocation(loc);
// if (primaryXMethod.isAbstract()) continue;
Set<XMethod> targetSet = null;
try {
if (clreplacedName.startsWith("[")) {
continue;
}
String methodSig = inv.getSignature(cpg);
if (!methodSig.endsWith("V") && !methodSig.endsWith("Exception;") && !methodSig.endsWith("Error;") && !methodSig.endsWith(")Ljava/lang/Object;")) {
continue;
}
targetSet = Hierarchy2.resolveMethodCallTargets(inv, typeFrame, cpg);
for (XMethod xMethod : targetSet) {
if (DEBUG) {
System.out.println("\tFound " + xMethod);
}
// Ignore abstract and native methods
boolean isUnconditionalThrower = isUnconditionalThrower(xMethod);
if (isUnconditionalThrower) {
if (!(xMethod.isFinal() || xMethod.isStatic() || xMethod.isPrivate())) {
try {
isExact = false;
XClreplaced xClreplaced = Global.getreplacedysisCache().getClreplacedreplacedysis(XClreplaced.clreplaced, xMethod.getClreplacedDescriptor());
if (xClreplaced.isAbstract()) {
continue;
}
} catch (CheckedreplacedysisException e) {
replacedysisContext.logError("Unable to resolve clreplaced for " + xMethod, e);
}
}
foundThrower = true;
if (DEBUG) {
System.out.println("Found thrower");
}
} else {
foundNonThrower = true;
if (DEBUG) {
System.out.println("Found non thrower");
}
}
}
} catch (ClreplacedNotFoundException e) {
replacedysisContext.getLookupFailureCallback().reportMissingClreplaced(e);
}
}
boolean newResult = foundThrower && !foundNonThrower;
if (newResult) {
if (!isExact) {
foundInexact = true;
}
// Method always throws an unhandled exception
// Remove the normal control flow edge from the CFG.
Edge fallThrough = cfg.getOutgoingEdgeWithType(basicBlock, FALL_THROUGH_EDGE);
if (fallThrough != null) {
if (DEBUG) {
System.out.println("\tREMOVING normal return for: " + primaryXMethod);
}
deletedEdgeSet.add(fallThrough);
}
}
}
if (!deletedEdgeSet.isEmpty()) {
cfgModified = true;
if (foundInexact) {
cfg.setFlag(CFG.FOUND_INEXACT_UNCONDITIONAL_THROWERS);
}
// Remove all edges marked for deletion
for (Edge edge : deletedEdgeSet) {
cfg.removeEdge(edge);
}
}
}
private boolean isUnconditionalThrower(XMethod xMethod) {
return xMethod.isUnconditionalThrower() && !xMethod.isUnsupported() && !xMethod.isSynthetic();
}
/**
* @param xMethod
* @param javaClreplaced
* @param method
* @return true if method unconditionally throws
* @deprecated Use {@link #doesMethodUnconditionallyThrowException(XMethod)}
* instead
*/
@Deprecated
static public Boolean doesMethodUnconditionallyThrowException(XMethod xMethod, JavaClreplaced javaClreplaced, Method method) {
return doesMethodUnconditionallyThrowException(xMethod);
}
/**
* @param xMethod
* @return true if method unconditionally throws
*/
static public boolean doesMethodUnconditionallyThrowException(XMethod xMethod) {
return xMethod.isUnconditionalThrower();
}
/**
* Return whether or not the CFG was modified.
*
* @return true if CFG was modified, false otherwise
*/
public boolean wasCFGModified() {
return cfgModified;
}
}
19
Source : LockAnalysis.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* replacedysis to determine where particular values are locked in a method. The
* dataflow values are maps of value numbers to the number of times those values
* are locked.
*
* @author David Hovemeyer
* @see ValueNumberreplacedysis
*/
public clreplaced Lockreplacedysis extends ForwardDataflowreplacedysis<LockSet> {
private static final boolean DEBUG = SystemProperties.getBoolean("la.debug");
private final MethodGen methodGen;
private final ValueNumberDataflow vnaDataflow;
private final ValueNumberreplacedysis vna;
private final boolean isSynchronized;
private final boolean isStatic;
public Lockreplacedysis(MethodGen methodGen, ValueNumberDataflow vnaDataflow, DepthFirstSearch dfs) {
super(dfs);
this.methodGen = methodGen;
this.vnaDataflow = vnaDataflow;
this.vna = vnaDataflow.getreplacedysis();
this.isSynchronized = methodGen.isSynchronized();
this.isStatic = methodGen.isStatic();
if (DEBUG) {
System.out.println("replacedyzing Locks in " + methodGen.getClreplacedName() + "." + methodGen.getName());
}
}
@Override
public LockSet createFact() {
return new LockSet();
}
@Override
public void copy(LockSet source, LockSet dest) {
dest.copyFrom(source);
}
@Override
public void initEntryFact(LockSet result) {
result.clear();
result.setDefaultLockCount(0);
if (isSynchronized && !isStatic) {
ValueNumber thisValue = vna.getThisValue();
result.setLockCount(thisValue.getNumber(), 1);
} else if (isSynchronized && isStatic) {
ValueNumber thisValue = vna.getClreplacedObjectValue(methodGen.getClreplacedName());
result.setLockCount(thisValue.getNumber(), 1);
}
}
@Override
public void makeFactTop(LockSet fact) {
fact.clear();
fact.setDefaultLockCount(LockSet.TOP);
}
@Override
public boolean isTop(LockSet fact) {
return fact.isTop();
}
@Override
public boolean same(LockSet fact1, LockSet fact2) {
return fact1.sameAs(fact2);
}
@Override
public void meetInto(LockSet fact, Edge edge, LockSet result) throws DataflowreplacedysisException {
result.meetWith(fact);
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, LockSet fact) throws DataflowreplacedysisException {
Instruction ins = handle.getInstruction();
short opcode = ins.getOpcode();
if (opcode == Const.MONITORENTER || opcode == Const.MONITOREXIT) {
ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock));
modifyLock(frame, fact, opcode == Const.MONITORENTER ? 1 : -1);
} else if (opcode == Const.INVOKEVIRTUAL || opcode == Const.INVOKEINTERFACE) {
InvokeInstruction inv = (InvokeInstruction) ins;
String name = inv.getMethodName(methodGen.getConstantPool());
String sig = inv.getSignature(methodGen.getConstantPool());
ValueNumberFrame frame = vnaDataflow.getFactAtLocation(new Location(handle, basicBlock));
if ("()V".equals(sig) && ("lock".equals(name) || "lockInterruptibly".equals(name))) {
modifyLock(frame, fact, 1);
} else if ("()V".equals(sig) && ("unlock".equals(name))) {
modifyLock(frame, fact, -1);
}
} else if ((ins instanceof ReturnInstruction) && isSynchronized && !isStatic) {
lockOp(fact, vna.getThisValue().getNumber(), -1);
}
}
private void modifyLock(ValueNumberFrame frame, LockSet fact, int delta) throws DataflowreplacedysisException {
if (frame.isValid()) {
int lockNumber = frame.getTopValue().getNumber();
lockOp(fact, lockNumber, delta);
}
}
private void lockOp(LockSet fact, int lockNumber, int delta) {
int value = fact.getLockCount(lockNumber);
if (value < 0) {
return;
}
value += delta;
if (value < 0) {
value = LockSet.BOTTOM;
}
if (DEBUG) {
System.out.println("Setting " + lockNumber + " to " + value + " in " + methodGen.getClreplacedName() + "." + methodGen.getName());
}
fact.setLockCount(lockNumber, value);
}
@Override
public boolean isFactValid(LockSet fact) {
return true;
}
// public static void main(String[] argv) throws Exception {
// if (argv.length != 1) {
// System.err.println("Usage: " + Lockreplacedysis.clreplaced.getName() +
// " <clreplacedfile>");
// System.exit(1);
// }
//
// DataflowTestDriver<LockSet, Lockreplacedysis> driver = new
// DataflowTestDriver<LockSet, Lockreplacedysis>() {
// @Override
// public Dataflow<LockSet, Lockreplacedysis> createDataflow(ClreplacedContext
// clreplacedContext, Method method)
// throws CFGBuilderException, DataflowreplacedysisException {
// return clreplacedContext.getLockDataflow(method);
// }
// };
//
// driver.execute(argv[0]);
// }
}
19
Source : LineNumberMap.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Summarize line numbers (and other source information) for a method.
*/
public clreplaced LineNumberMap {
/**
* Set this property to true to get debug print statements.
*/
private static final boolean DEBUG = SystemProperties.getBoolean("lnm.debug");
/**
* When this is true, the workaround for the bug in BCEL 5.0's
* LineNumberTable clreplaced is disabled.
*/
private static final boolean LINE_NUMBER_BUG = SystemProperties.getBoolean("lineNumberBug");
private final MethodGen methodGen;
private final IdenreplacedyHashMap<InstructionHandle, LineNumber> lineNumberMap;
private boolean hasLineNumbers;
/**
* Constructor.
*
* @param methodGen
* the method to summarize line numbers for
*/
public LineNumberMap(MethodGen methodGen) {
this.methodGen = methodGen;
lineNumberMap = new IdenreplacedyHashMap<>();
hasLineNumbers = false;
}
/**
* Build the line number information. Should be called before any other
* methods.
*/
public void build() {
int numGood = 0, numBytecodes = 0;
if (DEBUG) {
System.out.println("Method: " + methodGen.getName() + " - " + methodGen.getSignature() + "in clreplaced " + methodGen.getClreplacedName());
}
// replacedociate line number information with each InstructionHandle
LineNumberTable table = methodGen.getLineNumberTable(methodGen.getConstantPool());
if (table != null && table.getTableLength() > 0) {
checkTable(table);
InstructionHandle handle = methodGen.getInstructionList().getStart();
while (handle != null) {
int bytecodeOffset = handle.getPosition();
if (bytecodeOffset < 0) {
throw new IllegalStateException("Bad bytecode offset: " + bytecodeOffset);
}
if (DEBUG) {
System.out.println("Looking for source line for bytecode offset " + bytecodeOffset);
}
int sourceLine;
try {
sourceLine = table.getSourceLine(bytecodeOffset);
} catch (ArrayIndexOutOfBoundsException e) {
if (LINE_NUMBER_BUG) {
throw e;
} else {
sourceLine = -1;
}
}
if (sourceLine >= 0) {
++numGood;
}
lineNumberMap.put(handle, new LineNumber(bytecodeOffset, sourceLine));
handle = handle.getNext();
++numBytecodes;
}
hasLineNumbers = true;
if (DEBUG) {
System.out.println("\t" + numGood + "/" + numBytecodes + " had valid line numbers");
}
}
}
private void checkTable(LineNumberTable table) {
if (DEBUG) {
System.out.println("line number table has length " + table.getTableLength());
}
LineNumber[] entries = table.getLineNumberTable();
int lastBytecode = -1;
for (int i = 0; i < entries.length; ++i) {
LineNumber ln = entries[i];
if (DEBUG) {
System.out.println("Entry " + i + ": pc=" + ln.getStartPC() + ", line=" + ln.getLineNumber());
}
int pc = ln.getStartPC();
if (pc <= lastBytecode) {
throw new IllegalStateException("LineNumberTable is not sorted");
}
}
}
/**
* Does this method have line number information?
*/
public boolean hasLineNumbers() {
return hasLineNumbers;
}
/**
* Find the line number information for instruction whose handle is given.
*
* @param handle
* the InstructionHandle
* @return the LineNumber object containing bytecode offset and source line
* number
*/
public LineNumber lookupLineNumber(InstructionHandle handle) {
return lineNumberMap.get(handle);
}
}
19
Source : ExceptionHandlerMap.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
private void build(MethodGen methodGen) {
CodeExceptionGen[] handlerList = methodGen.getExceptionHandlers();
// Map handler start instructions to the actual exception handlers
for (CodeExceptionGen exceptionHandler : handlerList) {
addExceptionHandler(exceptionHandler);
}
// For each instruction, determine which handlers it can reach
InstructionHandle handle = methodGen.getInstructionList().getStart();
while (handle != null) {
int offset = handle.getPosition();
handlerLoop: for (CodeExceptionGen exceptionHandler : handlerList) {
int startOfRange = exceptionHandler.getStartPC().getPosition();
int endOfRange = exceptionHandler.getEndPC().getPosition();
if (offset >= startOfRange && offset <= endOfRange) {
// This handler is reachable from the instruction
addHandler(handle, exceptionHandler);
// If this handler handles all exception types
// i.e., an ANY handler, or catch(Throwable...),
// then no further (lower-priority)
// handlers are reachable from the instruction.
if (Hierarchy.isUniversalExceptionHandler(exceptionHandler.getCatchType())) {
break handlerLoop;
}
}
}
handle = handle.getNext();
}
}
19
Source : Dataflow.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
private String getFullyQualifiedMethodName() {
String methodName;
MethodGen methodGen = cfg.getMethodGen();
if (methodGen == null) {
methodName = cfg.getMethodName();
} else {
methodName = SignatureConverter.convertMethodSignature(methodGen);
}
return methodName;
}
19
Source : ConstantAnalysis.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Dataflow replacedysis to find constant values.
*
* @see edu.umd.cs.findbugs.ba.constant.Constant
* @author David Hovemeyer
*/
public clreplaced Constantreplacedysis extends FrameDataflowreplacedysis<Constant, ConstantFrame> {
private final MethodGen methodGen;
private final ConstantFrameModelingVisitor visitor;
public Constantreplacedysis(MethodGen methodGen, DepthFirstSearch dfs) {
super(dfs);
this.methodGen = methodGen;
this.visitor = new ConstantFrameModelingVisitor(methodGen.getConstantPool());
}
@Override
public ConstantFrame createFact() {
return new ConstantFrame(methodGen.getMaxLocals());
}
@Override
public void initEntryFact(ConstantFrame frame) {
frame.setValid();
frame.clearStack();
int numSlots = frame.getNumSlots();
for (int i = 0; i < numSlots; ++i) {
frame.setValue(i, Constant.NOT_CONSTANT);
}
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, ConstantFrame frame) throws DataflowreplacedysisException {
visitor.setFrameAndLocation(frame, new Location(handle, basicBlock));
visitor.replacedyzeInstruction(handle.getInstruction());
}
@Override
public void meetInto(ConstantFrame fact, Edge edge, ConstantFrame result) throws DataflowreplacedysisException {
if (fact.isValid()) {
ConstantFrame tmpFact = null;
if (edge.isExceptionEdge()) {
tmpFact = modifyFrame(fact, null);
tmpFact.clearStack();
tmpFact.pushValue(Constant.NOT_CONSTANT);
}
if (tmpFact != null) {
fact = tmpFact;
}
}
mergeInto(fact, result);
}
@Override
protected void mergeValues(ConstantFrame otherFrame, ConstantFrame resultFrame, int slot) throws DataflowreplacedysisException {
Constant value = Constant.merge(resultFrame.getValue(slot), otherFrame.getValue(slot));
resultFrame.setValue(slot, value);
}
// /*
// * Test driver.
// */
// public static void main(String[] argv) throws Exception {
// if (argv.length != 1) {
// System.err.println("Usage: " + Constantreplacedysis.clreplaced.getName() +
// " <clreplaced file>");
// System.exit(1);
// }
//
// DataflowTestDriver<ConstantFrame, Constantreplacedysis> driver =
// new DataflowTestDriver<ConstantFrame, Constantreplacedysis>() {
// @Override
// public Dataflow<ConstantFrame, Constantreplacedysis> createDataflow(
// ClreplacedContext clreplacedContext,
// Method method) throws CFGBuilderException, DataflowreplacedysisException {
// return clreplacedContext.getConstantDataflow(method);
// }
// };
//
// driver.execute(argv[0]);
// }
}
19
Source : CFGBuilderFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Create a CFGBuilder to build a CFG for given method.
*
* @param methodGen
* the method
* @return a CFGBuilder for the method
*/
public static CFGBuilder create(@Nonnull MethodDescriptor descriptor, @Nonnull MethodGen methodGen) {
return new BetterCFGBuilder2(descriptor, methodGen);
}
19
Source : CFG.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Simple control flow graph abstraction for BCEL.
*
* @see BasicBlock
* @see Edge
*/
public clreplaced CFG extends AbstractGraph<Edge, BasicBlock> implements Debug {
/*
* ----------------------------------------------------------------------
* CFG flags
* ----------------------------------------------------------------------
*/
/**
* Flag set if infeasible exception edges have been pruned from the CFG.
*/
public static final int PRUNED_INFEASIBLE_EXCEPTIONS = 1;
/**
* Flag set if normal return edges from calls to methods which
* unconditionally throw an exception have been removed.
*/
public static final int PRUNED_UNCONDITIONAL_THROWERS = 2;
/**
* Flag set if CFG has been "refined"; i.e., to the extent possible, all
* infeasible edges have been removed.
*/
public static final int REFINED = 4;
/**
* Flag set if CFG edges corresponding to failed replacedertions have been
* removed.
*/
public static final int PRUNED_FAILED_replacedERTION_EDGES = 8;
/**
* Flag set if CFG is busy (in the process of being refined.
*/
public static final int BUSY = 16;
public static final int FOUND_INEXACT_UNCONDITIONAL_THROWERS = 32;
/*
* ----------------------------------------------------------------------
* Helper clreplacedes
* ----------------------------------------------------------------------
*/
/**
* An Iterator over the Locations in the CFG. Because of JSR subroutines,
* the same instruction may actually be part of multiple basic blocks (with
* different facts true in each, due to calling context). Locations specify
* both the instruction and the basic block.
*/
private clreplaced LocationIterator implements Iterator<Location> {
private final Iterator<BasicBlock> blockIter;
private BasicBlock curBlock;
private Iterator<InstructionHandle> instructionIter;
private Location next;
private LocationIterator() {
this.blockIter = blockIterator();
findNext();
}
@Override
public boolean hasNext() {
findNext();
return next != null;
}
@Override
public Location next() {
findNext();
if (next == null) {
throw new NoSuchElementException();
}
Location result = next;
next = null;
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private void findNext() {
while (next == null) {
// Make sure we have an instruction iterator
if (instructionIter == null) {
if (!blockIter.hasNext()) {
// At end
return;
}
curBlock = blockIter.next();
instructionIter = curBlock.instructionIterator();
}
if (instructionIter.hasNext()) {
next = new Location(instructionIter.next(), curBlock);
} else {
// Go to next block
instructionIter = null;
}
}
}
}
/*
* ----------------------------------------------------------------------
* Fields
* ----------------------------------------------------------------------
*/
private BasicBlock entry, exit;
private int flags;
// for informational purposes
private String methodName;
private MethodGen methodGen;
private List<Edge> removedEdgeList;
/*
* ----------------------------------------------------------------------
* Public methods
* ----------------------------------------------------------------------
*/
/**
* Constructor. Creates empty control flow graph (with just entry and exit
* nodes).
*/
public CFG() {
}
/**
* @param methodName
* The methodName to set.
*/
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public void setMethodGen(MethodGen methodGen) {
this.methodGen = methodGen;
}
public MethodGen getMethodGen() {
return methodGen;
}
/**
* @return Returns the methodName.
*/
public String getMethodName() {
return methodName;
}
public String getMethodSig() {
return methodGen.getSignature();
}
public void setFlags(int flags) {
this.flags = flags;
}
public void setFlag(int flags) {
this.flags |= flags;
}
public void clearFlag(int flags) {
this.flags &= ~flags;
}
public int getFlags() {
return flags;
}
public boolean isFlagSet(int flag) {
return (flags & flag) != 0;
}
/**
* Get the entry node.
*/
public BasicBlock getEntry() {
if (entry == null) {
entry = allocate();
}
return entry;
}
/**
* Get the exit node.
*/
public BasicBlock getExit() {
if (exit == null) {
exit = allocate();
}
return exit;
}
/**
* Add a unique edge to the graph. There must be no other edge already in
* the CFG with the same source and destination blocks.
*
* @param source
* the source basic block
* @param dest
* the destination basic block
* @param type
* the type of edge; see constants in EdgeTypes interface
* @return the newly created Edge
* @throws IllegalStateException
* if there is already an edge in the CFG with the same source
* and destination block
*/
public Edge createEdge(BasicBlock source, BasicBlock dest, @Edge.Type int type) {
Edge edge = createEdge(source, dest);
edge.setType(type);
return edge;
}
/**
* Look up an Edge by its id.
*
* @param id
* the id of the edge to look up
* @return the Edge, or null if no matching Edge was found
*/
public Edge lookupEdgeById(int id) {
Iterator<Edge> i = edgeIterator();
while (i.hasNext()) {
Edge edge = i.next();
if (edge.getId() == id) {
return edge;
}
}
return null;
}
/**
* Look up a BasicBlock by its unique label.
*
* @param blockLabel
* the label of a BasicBlock
* @return the BasicBlock with the given label, or null if there is no such
* BasicBlock
*/
public BasicBlock lookupBlockByLabel(int blockLabel) {
for (Iterator<BasicBlock> i = blockIterator(); i.hasNext(); ) {
BasicBlock basicBlock = i.next();
if (basicBlock.getLabel() == blockLabel) {
return basicBlock;
}
}
return null;
}
/**
* Get an Iterator over the nodes (BasicBlocks) of the control flow graph.
*/
public Iterator<BasicBlock> blockIterator() {
return vertexIterator();
}
/*
* * Get an Iteratable over the nodes (BasicBlocks) of the control flow
* graph.
*/
public Iterable<BasicBlock> blocks() {
return vertices();
}
/**
* Get an Iterator over the Locations in the control flow graph.
*/
public Iterator<Location> locationIterator() {
return new LocationIterator();
}
/**
* Get an Iterator over the Locations in the control flow graph.
*/
public Iterable<Location> locations() {
return () -> locationIterator();
}
/**
* Returns a collection of locations, ordered according to the compareTo
* ordering over locations. If you want to list all the locations in a CFG
* for debugging purposes, this is a good order to do so in.
*
* @return collection of locations
*/
public Collection<Location> orderedLocations() {
TreeSet<Location> tree = new TreeSet<>();
for (Iterator<Location> locs = locationIterator(); locs.hasNext(); ) {
Location loc = locs.next();
tree.add(loc);
}
return tree;
}
/**
* Get Collection of basic blocks whose IDs are specified by given BitSet.
*
* @param labelSet
* BitSet of block labels
* @return a Collection containing the blocks whose IDs are given
*/
public Collection<BasicBlock> getBlocks(BitSet labelSet) {
LinkedList<BasicBlock> result = new LinkedList<>();
for (Iterator<BasicBlock> i = blockIterator(); i.hasNext(); ) {
BasicBlock block = i.next();
if (labelSet.get(block.getLabel())) {
result.add(block);
}
}
return result;
}
/**
* Get a Collection of basic blocks which contain the bytecode instruction
* with given offset.
*
* @param offset
* the bytecode offset of an instruction
* @return Collection of BasicBlock objects which contain the instruction
* with that offset
*/
public Collection<BasicBlock> getBlocksContainingInstructionWithOffset(int offset) {
LinkedList<BasicBlock> result = new LinkedList<>();
for (Iterator<BasicBlock> i = blockIterator(); i.hasNext(); ) {
BasicBlock block = i.next();
if (block.containsInstructionWithOffset(offset)) {
result.add(block);
}
}
return result;
}
/**
* Get a Collection of Locations which specify the instruction at given
* bytecode offset.
*
* @param offset
* the bytecode offset
* @return all Locations referring to the instruction at that offset
*/
public Collection<Location> getLocationsContainingInstructionWithOffset(int offset) {
LinkedList<Location> result = new LinkedList<>();
for (Iterator<Location> i = locationIterator(); i.hasNext(); ) {
Location location = i.next();
if (location.getHandle().getPosition() == offset) {
result.add(location);
}
}
return result;
}
/**
* Get the first predecessor reachable from given edge type.
*
* @param target
* the target block
* @param edgeType
* the edge type leading from the predecessor
* @return the predecessor, or null if there is no incoming edge with the
* specified edge type
*/
public BasicBlock getPredecessorWithEdgeType(BasicBlock target, @Type int edgeType) {
Edge edge = getIncomingEdgeWithType(target, edgeType);
return edge != null ? edge.getSource() : null;
}
/**
* Get the first successor reachable from given edge type.
*
* @param source
* the source block
* @param edgeType
* the edge type leading to the successor
* @return the successor, or null if there is no outgoing edge with the
* specified edge type
*/
public BasicBlock getSuccessorWithEdgeType(BasicBlock source, @Type int edgeType) {
Edge edge = getOutgoingEdgeWithType(source, edgeType);
return edge != null ? edge.getTarget() : null;
}
/**
* Get the Location where exception(s) thrown on given exception edge are
* thrown.
*
* @param exceptionEdge
* the exception Edge
* @return Location where exception(s) are thrown from
*/
public Location getExceptionThrowerLocation(Edge exceptionEdge) {
if (!exceptionEdge.isExceptionEdge()) {
throw new IllegalArgumentException();
}
InstructionHandle handle = exceptionEdge.getSource().getExceptionThrower();
if (handle == null) {
throw new IllegalStateException();
}
BasicBlock basicBlock = (handle.getInstruction() instanceof ATHROW) ? exceptionEdge.getSource() : getSuccessorWithEdgeType(exceptionEdge.getSource(), EdgeTypes.FALL_THROUGH_EDGE);
if (basicBlock == null && removedEdgeList != null) {
// The fall-through edge might have been removed during
// CFG pruning. Look for it in the removed edge list.
for (Edge removedEdge : removedEdgeList) {
if (removedEdge.getType() == EdgeTypes.FALL_THROUGH_EDGE && removedEdge.getSource() == exceptionEdge.getSource()) {
basicBlock = removedEdge.getTarget();
break;
}
}
}
if (basicBlock == null) {
throw new IllegalStateException("No basic block for thrower " + handle + " in " + this.methodGen.getClreplacedName() + "." + this.methodName + " : " + this.methodGen.getSignature());
}
return new Location(handle, basicBlock);
}
/**
* Get an Iterator over Edges removed from this CFG.
*
* @return Iterator over Edges removed from this CFG
*/
public Iterator<Edge> removedEdgeIterator() {
return removedEdgeList != null ? removedEdgeList.iterator() : new NullIterator<>();
}
/**
* Get the first incoming edge in basic block with given type.
*
* @param basicBlock
* the basic block
* @param edgeType
* the edge type
* @return the Edge, or null if there is no edge with that edge type
*/
public Edge getIncomingEdgeWithType(BasicBlock basicBlock, @Type int edgeType) {
return getEdgeWithType(incomingEdgeIterator(basicBlock), edgeType);
}
/**
* Get the first outgoing edge in basic block with given type.
*
* @param basicBlock
* the basic block
* @param edgeType
* the edge type
* @return the Edge, or null if there is no edge with that edge type
*/
public Edge getOutgoingEdgeWithType(BasicBlock basicBlock, @Type int edgeType) {
return getEdgeWithType(outgoingEdgeIterator(basicBlock), edgeType);
}
private Edge getEdgeWithType(Iterator<Edge> iter, @Type int edgeType) {
while (iter.hasNext()) {
Edge edge = iter.next();
if (edge.getType() == edgeType) {
return edge;
}
}
return null;
}
/**
* Allocate a new BasicBlock. The block won't be connected to any node in
* the graph.
*/
public BasicBlock allocate() {
BasicBlock b = new BasicBlock();
addVertex(b);
return b;
}
/**
* Get number of basic blocks. This is just here for compatibility with the
* old CFG method names.
*/
public int getNumBasicBlocks() {
return getNumVertices();
}
/**
* Get the number of edge labels allocated. This is just here for
* compatibility with the old CFG method names.
*/
public int getMaxEdgeId() {
return getNumEdgeLabels();
}
public void checkIntegrity() {
// Ensure that basic blocks have only consecutive instructions
for (Iterator<BasicBlock> i = blockIterator(); i.hasNext(); ) {
BasicBlock basicBlock = i.next();
InstructionHandle prev = null;
for (Iterator<InstructionHandle> j = basicBlock.instructionIterator(); j.hasNext(); ) {
InstructionHandle handle = j.next();
if (prev != null && prev.getNext() != handle) {
throw new IllegalStateException("Non-consecutive instructions in block " + basicBlock.getLabel() + ": prev=" + prev + ", handle=" + handle);
}
prev = handle;
}
}
}
@Override
protected Edge allocateEdge(BasicBlock source, BasicBlock target) {
return new Edge(source, target);
}
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.graph.AbstractGraph#removeEdge(edu.umd.cs.findbugs
* .graph.AbstractEdge)
*/
@Override
public void removeEdge(Edge edge) {
super.removeEdge(edge);
// Keep track of removed edges.
if (removedEdgeList == null) {
removedEdgeList = new LinkedList<>();
}
removedEdgeList.add(edge);
}
/**
* Get number of non-exception control successors of given basic block.
*
* @param block
* a BasicBlock
* @return number of non-exception control successors of the basic block
*/
public int getNumNonExceptionSucessors(BasicBlock block) {
int numNonExceptionSuccessors = block.getNumNonExceptionSuccessors();
if (numNonExceptionSuccessors < 0) {
numNonExceptionSuccessors = 0;
for (Iterator<Edge> i = outgoingEdgeIterator(block); i.hasNext(); ) {
Edge edge = i.next();
if (!edge.isExceptionEdge()) {
numNonExceptionSuccessors++;
}
}
block.setNumNonExceptionSuccessors(numNonExceptionSuccessors);
}
return numNonExceptionSuccessors;
}
/**
* Get the Location representing the entry to the CFG. Note that this is a
* "fake" Location, and shouldn't be relied on to yield source line
* information.
*
* @return Location at entry to CFG
*/
public Location getLocationAtEntry() {
InstructionHandle handle = getEntry().getFirstInstruction();
replacedert handle != null;
return new Location(handle, getEntry());
}
public Location getPreviousLocation(Location loc) {
InstructionHandle handle = loc.getHandle();
BasicBlock basicBlock = loc.getBasicBlock();
if (basicBlock.getFirstInstruction().equals(handle)) {
BasicBlock prevBlock = basicBlock;
while (true) {
prevBlock = getPredecessorWithEdgeType(prevBlock, EdgeTypes.FALL_THROUGH_EDGE);
if (prevBlock == null) {
return loc;
}
handle = prevBlock.getLastInstruction();
if (handle != null) {
return new Location(handle, prevBlock);
}
}
} else {
handle = handle.getPrev();
return new Location(handle, basicBlock);
}
}
}
19
Source : CFG.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
public void setMethodGen(MethodGen methodGen) {
this.methodGen = methodGen;
}
19
Source : BetterCFGBuilder2.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* A CFGBuilder that really tries to construct accurate control flow graphs. The
* CFGs it creates have accurate exception edges, and have accurately inlined
* JSR subroutines.
*
* @author David Hovemeyer
* @see CFG
*/
public clreplaced BetterCFGBuilder2 implements CFGBuilder, EdgeTypes, Debug {
private static final boolean DEBUG = SystemProperties.getBoolean("cfgbuilder.debug");
/*
* ----------------------------------------------------------------------
* Helper clreplacedes
* ----------------------------------------------------------------------
*/
/**
* A work list item for creating the CFG for a subroutine.
*/
private static clreplaced WorkLisreplacedem {
private final InstructionHandle start;
private final BasicBlock basicBlock;
/**
* Constructor.
*
* @param start
* first instruction in the basic block
* @param basicBlock
* the basic block to build
*/
public WorkLisreplacedem(InstructionHandle start, BasicBlock basicBlock) {
this.start = start;
this.basicBlock = basicBlock;
}
/**
* Get the start instruction.
*/
public InstructionHandle getStartInstruction() {
return start;
}
/**
* Get the basic block.
*/
public BasicBlock getBasicBlock() {
return basicBlock;
}
}
/**
* A placeholder for a control edge that escapes its subroutine to return
* control back to an outer (calling) subroutine. It will turn into a real
* edge during inlining.
*/
private static clreplaced EscapeTarget {
private final InstructionHandle target;
@Edge.Type
private final int edgeType;
/**
* Constructor.
*
* @param target
* the target instruction in a calling subroutine
* @param edgeType
* the type of edge that should be created when the
* subroutine is inlined into its calling context
*/
public EscapeTarget(InstructionHandle target, @Edge.Type int edgeType) {
this.target = target;
this.edgeType = edgeType;
}
/**
* Get the target instruction.
*/
public InstructionHandle getTarget() {
return target;
}
/**
* Get the edge type.
*/
@Edge.Type
public int getEdgeType() {
return edgeType;
}
}
/**
* JSR subroutine. The top level subroutine is where execution starts. Each
* subroutine has its own CFG. Eventually, all JSR subroutines will be
* inlined into the top level subroutine, resulting in an accurate CFG for
* the overall method.
*/
private clreplaced Subroutine {
private final InstructionHandle start;
private final BitSet instructionSet;
private final CFG cfgSub;
private final IdenreplacedyHashMap<InstructionHandle, BasicBlock> blockMap;
private final IdenreplacedyHashMap<BasicBlock, List<EscapeTarget>> escapeTargetListMap;
private final BitSet returnBlockSet;
private final BitSet exitBlockSet;
private final BitSet unhandledExceptionBlockSet;
private final LinkedList<WorkLisreplacedem> workList;
/**
* Constructor.
*
* @param start
* the start instruction for the subroutine
*/
public Subroutine(InstructionHandle start) {
this.start = start;
this.instructionSet = new BitSet();
this.cfgSub = new CFG();
this.blockMap = new IdenreplacedyHashMap<>();
this.escapeTargetListMap = new IdenreplacedyHashMap<>();
this.returnBlockSet = new BitSet();
this.exitBlockSet = new BitSet();
this.unhandledExceptionBlockSet = new BitSet();
this.workList = new LinkedList<>();
}
/**
* Get the start instruction.
*/
public InstructionHandle getStartInstruction() {
return start;
}
/**
* Allocate a new basic block in the subroutine.
*/
public BasicBlock allocateBasicBlock() {
return cfgSub.allocate();
}
/**
* Add a work list item for a basic block to be constructed.
*/
public void addItem(WorkLisreplacedem item) {
workList.add(item);
}
/**
* Are there more work list items?
*/
public boolean hasMoreWork() {
return !workList.isEmpty();
}
/**
* Get the next work list item.
*/
public WorkLisreplacedem nexreplacedem() {
return workList.removeFirst();
}
/**
* Get the entry block for the subroutine's CFG.
*/
public BasicBlock getEntry() {
return cfgSub.getEntry();
}
/**
* Get the exit block for the subroutine's CFG.
*/
public BasicBlock getExit() {
return cfgSub.getExit();
}
/**
* Get the start block for the subroutine's CFG. (I.e., the block
* containing the start instruction.)
*/
public BasicBlock getStartBlock() {
return getBlock(start);
}
/**
* Get the subroutine's CFG.
*/
public CFG getCFG() {
return cfgSub;
}
/**
* Add an instruction to the subroutine. We keep track of which
* instructions are part of which subroutines. No instruction may be
* part of more than one subroutine.
*
* @param handle
* the instruction to be added to the subroutine
*/
public void addInstruction(InstructionHandle handle) throws CFGBuilderException {
int position = handle.getPosition();
if (usedInstructionSet.get(position)) {
throw new CFGBuilderException("Instruction " + handle + " visited in multiple subroutines");
}
instructionSet.set(position);
usedInstructionSet.set(position);
}
/**
* Is the given instruction part of this subroutine?
*/
public boolean containsInstruction(InstructionHandle handle) {
return instructionSet.get(handle.getPosition());
}
/**
* Get the basic block in the subroutine for the given instruction. If
* the block doesn't exist yet, it is created, and a work list item is
* added which will populate it. Note that if start is an exception
* thrower, the block returned will be its ETB.
*
* @param start
* the start instruction for the block
* @return the basic block for the instruction
*/
public BasicBlock getBlock(InstructionHandle start) {
BasicBlock block = blockMap.get(start);
if (block == null) {
block = allocateBasicBlock();
blockMap.put(start, block);
// Block is an exception handler?
CodeExceptionGen exceptionGen = exceptionHandlerMap.getHandlerForStartInstruction(start);
if (exceptionGen != null) {
block.setExceptionGen(null, exceptionGen);
}
addItem(new WorkLisreplacedem(start, block));
}
return block;
}
/**
* Indicate that the method returns at the end of the given block.
*
* @param block
* the returning block
*/
public void setReturnBlock(BasicBlock block) {
returnBlockSet.set(block.getLabel());
}
/**
* Does the method return at the end of this block?
*/
public boolean isReturnBlock(BasicBlock block) {
return returnBlockSet.get(block.getLabel());
}
/**
* Indicate that System.exit() is called at the end of the given block.
*
* @param block
* the exiting block
*/
public void setExitBlock(BasicBlock block) {
exitBlockSet.set(block.getLabel());
}
/**
* Is System.exit() called at the end of this block?
*/
public boolean isExitBlock(BasicBlock block) {
return exitBlockSet.get(block.getLabel());
}
/**
* Indicate that an unhandled exception may be thrown by the given
* block.
*
* @param block
* the block throwing an unhandled exception
*/
public void setUnhandledExceptionBlock(BasicBlock block) {
unhandledExceptionBlockSet.set(block.getLabel());
}
/**
* Does this block throw an unhandled exception?
*/
public boolean isUnhandledExceptionBlock(BasicBlock block) {
return unhandledExceptionBlockSet.get(block.getLabel());
}
/**
* Add a control flow edge to the subroutine. If the control target has
* not yet been added to the subroutine, a new work list item is added.
* If the control target is in another subroutine, an EscapeTarget is
* added.
*
* @param sourceBlock
* the source basic block
* @param target
* the control target
* @param edgeType
* the type of control edge
*/
public void addEdgeAndExplore(BasicBlock sourceBlock, InstructionHandle target, @Edge.Type int edgeType) {
if (usedInstructionSet.get(target.getPosition()) && !containsInstruction(target)) {
// Control escapes this subroutine
List<EscapeTarget> escapeTargetList = escapeTargetListMap.computeIfAbsent(sourceBlock, k -> new LinkedList<>());
escapeTargetList.add(new EscapeTarget(target, edgeType));
} else {
// Edge within the current subroutine
BasicBlock targetBlock = getBlock(target);
addEdge(sourceBlock, targetBlock, edgeType);
}
}
/**
* Add an edge to the subroutine's CFG.
*
* @param sourceBlock
* the source basic block
* @param destBlock
* the destination basic block
* @param edgeType
* the type of edge
*/
public void addEdge(BasicBlock sourceBlock, BasicBlock destBlock, @Edge.Type int edgeType) {
if (VERIFY_INTEGRITY && destBlock.isExceptionHandler() && edgeType != HANDLED_EXCEPTION_EDGE) {
throw new IllegalStateException("In method " + SignatureConverter.convertMethodSignature(methodGen) + ": exception handler " + destBlock.getFirstInstruction() + " reachable by non exception edge type " + edgeType);
}
cfgSub.createEdge(sourceBlock, destBlock, edgeType);
}
/**
* Get an Iterator over the EscapeTargets of given basic block.
*
* @param sourceBlock
* the basic block
* @return an Iterator over the EscapeTargets
*/
public Iterator<EscapeTarget> escapeTargereplacederator(BasicBlock sourceBlock) {
List<EscapeTarget> escapeTargetList = escapeTargetListMap.get(sourceBlock);
if (escapeTargetList == null) {
escapeTargetList = Collections.emptyList();
}
return escapeTargetList.iterator();
}
}
/**
* Inlining context. This essentially consists of a inlining site and a
* subroutine to be inlined. A stack of calling contexts is maintained in
* order to resolve EscapeTargets.
*/
private static clreplaced Context {
private final Context caller;
private final Subroutine subroutine;
private final CFG result;
private final IdenreplacedyHashMap<BasicBlock, BasicBlock> blockMap;
private final LinkedList<BasicBlock> workList;
/**
* Constructor.
*
* @param caller
* the calling context
* @param subroutine
* the subroutine being inlined
* @param result
* the result CFG
*/
public Context(@Nullable Context caller, Subroutine subroutine, CFG result) {
this.caller = caller;
this.subroutine = subroutine;
this.result = result;
this.blockMap = new IdenreplacedyHashMap<>();
this.workList = new LinkedList<>();
}
/**
* Get the calling context.
*/
public Context getCaller() {
return caller;
}
/**
* Get the subroutine being inlined.
*/
public Subroutine getSubroutine() {
return subroutine;
}
/**
* Get the result CFG.
*/
public CFG getResult() {
return result;
}
/**
* Add a basic block to the inlining work list.
*
* public void addItem(BasicBlock item) {
* workList.add(item);
* }
*/
/**
* Are there more work list items?
*/
public boolean hasMoreWork() {
return !workList.isEmpty();
}
/**
* Get the next work list item (basic block to be inlined).
*/
public BasicBlock nexreplacedem() {
return workList.removeFirst();
}
/**
* Map a basic block in a subroutine to the corresponding block in the
* resulting CFG.
*
* @param subBlock
* the subroutine block
* @param resultBlock
* the result CFG block
*/
public void mapBlock(BasicBlock subBlock, BasicBlock resultBlock) {
blockMap.put(subBlock, resultBlock);
}
/**
* Get the block in the result CFG corresponding to the given subroutine
* block.
*
* @param subBlock
* the subroutine block
* @return the result CFG block
*/
public BasicBlock getBlock(BasicBlock subBlock) {
BasicBlock resultBlock = blockMap.get(subBlock);
if (resultBlock == null) {
resultBlock = result.allocate();
blockMap.put(subBlock, resultBlock);
workList.add(subBlock);
}
return resultBlock;
}
/**
* Check to ensure that this context is not the result of recursion.
*/
public void checkForRecursion() throws CFGBuilderException {
Context callerContext = caller;
while (callerContext != null) {
if (callerContext.subroutine == this.subroutine) {
throw new CFGBuilderException("JSR recursion detected!");
}
callerContext = callerContext.caller;
}
}
}
/*
* ----------------------------------------------------------------------
* Instance data
* ----------------------------------------------------------------------
*/
private final MethodGen methodGen;
private final ConstantPoolGen cpg;
private final ExceptionHandlerMap exceptionHandlerMap;
private final BitSet usedInstructionSet;
private final LinkedList<Subroutine> subroutineWorkList;
private final IdenreplacedyHashMap<InstructionHandle, Subroutine> jsrSubroutineMap;
private final Map<FieldDescriptor, Integer> addedFields = new HashMap<>();
private Subroutine topLevelSubroutine;
private CFG cfg;
/*
* ----------------------------------------------------------------------
* Public methods
* ----------------------------------------------------------------------
*/
/**
* Constructor.
*
* @param methodGen
* the method to build a CFG for
*/
public BetterCFGBuilder2(@Nonnull MethodDescriptor descriptor, @Nonnull MethodGen methodGen) {
this.methodGen = methodGen;
this.cpg = methodGen.getConstantPool();
IreplacedysisCache replacedysisCache = Global.getreplacedysisCache();
StandardTypeMerger merger = null;
ExceptionSetFactory exceptionSetFactory;
try {
exceptionSetFactory = replacedysisCache.getMethodreplacedysis(ExceptionSetFactory.clreplaced, descriptor);
merger = new StandardTypeMerger(replacedysisContext.currentreplacedysisContext().getLookupFailureCallback(), exceptionSetFactory);
} catch (CheckedreplacedysisException e) {
replacedysisContext.logError("Unable to generate exceptionSetFactory for " + descriptor, e);
}
this.exceptionHandlerMap = new ExceptionHandlerMap(methodGen, merger);
this.usedInstructionSet = new BitSet();
this.jsrSubroutineMap = new IdenreplacedyHashMap<>();
this.subroutineWorkList = new LinkedList<>();
}
public int getIndex(FieldDescriptor f) {
Integer i = addedFields.get(f);
if (i != null) {
return i;
}
int index = cpg.addFieldref(f.getSlashedClreplacedName(), f.getName(), f.getSignature());
addedFields.put(f, index);
return index;
}
public void optimize(InstructionList instructionList) {
InstructionHandle head = instructionList.getStart();
while (head != null) {
Instruction i = head.getInstruction();
if (i instanceof INVOKESTATIC) {
INVOKESTATIC is = (INVOKESTATIC) i;
String name = is.getMethodName(cpg);
String signature = is.getSignature(cpg);
if (name.startsWith("access$")) {
XMethod invoked = XFactory.createXMethod(is, cpg);
FieldDescriptor field = invoked.getAccessMethodForField();
if (field != null) {
boolean isSetter = signature.endsWith("V");
Instruction replacement;
int index = getIndex(field);
if (field.isStatic()) {
if (isSetter) {
replacement = new PUTSTATIC(index);
} else {
replacement = new GETSTATIC(index);
}
} else {
if (isSetter) {
replacement = new PUTFIELD(index);
} else {
replacement = new GETFIELD(index);
}
}
head.swapInstruction(replacement);
/*
if (false)
System.out.println("Subsreplaceduting " + (isSetter ? "set" : "get") + " of " + field + " for call of "
+ invoked + " in " + methodGen.getClreplacedName() + "." + methodGen.getName()
+ methodGen.getSignature());
*/
}
}
}
if (i instanceof IfInstruction) {
IfInstruction ii = (IfInstruction) i;
InstructionHandle target = ii.getTarget();
InstructionHandle next = head.getNext();
if (target.equals(next)) {
int consumed = ii.consumeStack(methodGen.getConstantPool());
if (consumed != 1 && consumed != 2) {
throw new IllegalStateException();
}
head.swapInstruction(consumed == 1 ? new POP() : new POP2());
}
}
if (i instanceof IFNULL || i instanceof IFNONNULL) {
IfInstruction ii = (IfInstruction) i;
InstructionHandle target = ii.getTarget();
// ICONST
InstructionHandle next1 = head.getNext();
if (next1 == null) {
break;
}
if (next1.getInstruction() instanceof ICONST) {
// GOTO
InstructionHandle next2 = next1.getNext();
if (next2 == null) {
break;
}
// ICONST
InstructionHandle next3 = next2.getNext();
if (next3 == null) {
break;
}
InstructionHandle next4 = next3.getNext();
if (next4 == null) {
break;
}
if (target.equals(next3) && next2.getInstruction() instanceof GOTO && next3.getInstruction() instanceof ICONST && next1.getTargeters().length == 0 && next2.getTargeters().length == 0 && next3.getTargeters().length == 1 && next4.getTargeters().length == 1) {
int c1 = ((ICONST) next1.getInstruction()).getValue().intValue();
GOTO g = (GOTO) next2.getInstruction();
int c2 = ((ICONST) next3.getInstruction()).getValue().intValue();
if (g.getTarget().equals(next4) && (c1 == 1 && c2 == 0 || c1 == 0 && c2 == 1)) {
boolean nullIsTrue = i instanceof IFNULL && c2 == 1 || i instanceof IFNONNULL && c2 == 0;
if (nullIsTrue) {
// System.out.println("Found NULL2Z instruction");
head.swapInstruction(new NULL2Z());
} else {
// System.out.println("Found NONNULL2Z instruction");
head.swapInstruction(new NONNULL2Z());
}
next3.removeAllTargeters();
next4.removeAllTargeters();
next1.swapInstruction(new NOP());
next2.swapInstruction(new NOP());
next3.swapInstruction(new NOP());
}
}
}
}
if (i instanceof ACONST_NULL) {
InstructionHandle next = head.getNext();
replacedert next != null;
InstructionHandle next2 = next.getNext();
if (next2 != null && next.getInstruction() instanceof ALOAD) {
Instruction check = next2.getInstruction();
if (check instanceof IF_ACMPNE || check instanceof IF_ACMPEQ) {
// need to update
head.swapInstruction(new NOP());
IfInstruction ifTest = (IfInstruction) check;
if (check instanceof IF_ACMPNE) {
next2.swapInstruction(new IFNONNULL(ifTest.getTarget()));
} else {
next2.swapInstruction(new IFNULL(ifTest.getTarget()));
}
}
}
}
head = head.getNext();
}
}
@Override
public void build() throws CFGBuilderException {
InstructionList instructionList = methodGen.getInstructionList();
optimize(instructionList);
topLevelSubroutine = new Subroutine(instructionList.getStart());
subroutineWorkList.add(topLevelSubroutine);
// Build top level subroutine and all JSR subroutines
while (!subroutineWorkList.isEmpty()) {
Subroutine subroutine = subroutineWorkList.removeFirst();
if (DEBUG) {
System.out.println("Starting subroutine " + subroutine.getStartInstruction());
}
build(subroutine);
}
// Inline everything into the top level subroutine
cfg = inlineAll();
// Add a NOP instruction to the entry block.
// This allows replacedyses to construct a Location
// representing the entry to the method.
BasicBlock entryBlock = cfg.getEntry();
InstructionList il = new InstructionList();
entryBlock.addInstruction(il.append(new NOP()));
cfg.checkIntegrity();
}
@Override
public CFG getCFG() {
return cfg;
}
/*
* ----------------------------------------------------------------------
* Implementation
* ----------------------------------------------------------------------
*/
/**
* Build a subroutine. We iteratively add basic blocks to the subroutine
* until there are no more blocks reachable from the calling context. As JSR
* instructions are encountered, new Subroutines are added to the subroutine
* work list.
*
* @param subroutine
* the subroutine
*/
private void build(Subroutine subroutine) throws CFGBuilderException {
// Prime the work list
subroutine.addEdgeAndExplore(subroutine.getEntry(), subroutine.getStartInstruction(), START_EDGE);
// Keep going until all basic blocks in the subroutine have been added
while (subroutine.hasMoreWork()) {
WorkLisreplacedem item = subroutine.nexreplacedem();
InstructionHandle handle = item.getStartInstruction();
BasicBlock basicBlock = item.getBasicBlock();
// Add exception handler block (ETB) for exception-throwing
// instructions
if (isPEI(handle)) {
if (DEBUG) {
System.out.println("ETB block " + basicBlock.getLabel() + " for " + handle);
}
handleExceptions(subroutine, handle, basicBlock);
BasicBlock body = subroutine.allocateBasicBlock();
subroutine.addEdge(basicBlock, body, FALL_THROUGH_EDGE);
basicBlock = body;
}
if (DEBUG) {
System.out.println("BODY block " + basicBlock.getLabel() + " for " + handle);
}
if (!basicBlock.isEmpty()) {
throw new IllegalStateException("Block isn't empty!");
}
// Add instructions until we get to the end of the block
boolean endOfBasicBlock = false;
do {
Instruction ins = handle.getInstruction();
// Add the instruction to the block
if (DEBUG) {
System.out.println("BB " + basicBlock.getLabel() + ": adding" + handle);
}
basicBlock.addInstruction(handle);
subroutine.addInstruction(handle);
short opcode = ins.getOpcode();
// TODO: should check instruction to ensure that in a JSR
// subroutine
// no replacedignments are made to the local containing the return
// address.
// if (ins instanceof ASTORE) ...
if (opcode == Const.JSR || opcode == Const.JSR_W) {
// Find JSR subroutine, add it to subroutine work list if
// we haven't built a CFG for it yet
JsrInstruction jsr = (JsrInstruction) ins;
InstructionHandle jsrTarget = jsr.getTarget();
Subroutine jsrSubroutine = jsrSubroutineMap.get(jsrTarget);
if (jsrSubroutine == null) {
jsrSubroutine = new Subroutine(jsrTarget);
jsrSubroutineMap.put(jsrTarget, jsrSubroutine);
subroutineWorkList.add(jsrSubroutine);
}
// This ends the basic block.
// Add a JSR_EDGE to the successor.
// It will be replaced later by the inlined JSR subroutine.
subroutine.addEdgeAndExplore(basicBlock, handle.getNext(), JSR_EDGE);
endOfBasicBlock = true;
} else if (opcode == Const.RET) {
// End of JSR subroutine
subroutine.addEdge(basicBlock, subroutine.getExit(), RET_EDGE);
endOfBasicBlock = true;
} else {
TargetEnumeratingVisitor visitor = new TargetEnumeratingVisitor(handle, cpg);
if (visitor.isEndOfBasicBlock()) {
endOfBasicBlock = true;
// Add control edges as appropriate
if (visitor.instructionIsThrow()) {
handleExceptions(subroutine, handle, basicBlock);
} else if (visitor.instructionIsExit()) {
subroutine.setExitBlock(basicBlock);
} else if (visitor.instructionIsReturn()) {
subroutine.setReturnBlock(basicBlock);
} else {
Iterator<Target> i = visitor.targereplacederator();
while (i.hasNext()) {
Target target = i.next();
subroutine.addEdgeAndExplore(basicBlock, target.getTargetInstruction(), target.getEdgeType());
}
}
}
}
if (!endOfBasicBlock) {
InstructionHandle next = handle.getNext();
if (next == null) {
throw new CFGBuilderException("Control falls off end of method: " + handle);
}
// Is the next instruction a control merge or a PEI?
if (isMerge(next) || isPEI(next)) {
subroutine.addEdgeAndExplore(basicBlock, next, FALL_THROUGH_EDGE);
endOfBasicBlock = true;
} else {
// Basic block continues
handle = next;
}
}
} while (!endOfBasicBlock);
}
}
/**
* Add exception edges for given instruction.
*
* @param subroutine
* the subroutine containing the instruction
* @param pei
* the instruction which throws an exception
* @param etb
* the exception thrower block (ETB) for the instruction
*/
private void handleExceptions(Subroutine subroutine, InstructionHandle pei, BasicBlock etb) {
etb.setExceptionThrower(pei);
// Remember whether or not a universal exception handler
// is reachable. If so, then we know that exceptions raised
// at this instruction cannot propagate out of the method.
boolean sawUniversalExceptionHandler = false;
List<CodeExceptionGen> exceptionHandlerList = exceptionHandlerMap.getHandlerList(pei);
if (exceptionHandlerList != null) {
for (CodeExceptionGen exceptionHandler : exceptionHandlerList) {
InstructionHandle handlerStart = exceptionHandler.getHandlerPC();
subroutine.addEdgeAndExplore(etb, handlerStart, HANDLED_EXCEPTION_EDGE);
if (Hierarchy.isUniversalExceptionHandler(exceptionHandler.getCatchType())) {
sawUniversalExceptionHandler = true;
}
}
}
// If required, mark this block as throwing an unhandled exception.
// For now, we replacedume that if there is no reachable handler that handles
// ANY exception type, then the exception can be thrown out of the
// method.
if (!sawUniversalExceptionHandler) {
if (DEBUG) {
System.out.println("Adding unhandled exception edge from " + pei);
}
subroutine.setUnhandledExceptionBlock(etb);
}
}
/**
* Return whether or not the given instruction can throw exceptions.
*
* @param handle
* the instruction
* @return true if the instruction can throw an exception, false otherwise
* @throws CFGBuilderException
*/
private boolean isPEI(InstructionHandle handle) throws CFGBuilderException {
Instruction ins = handle.getInstruction();
if (!(ins instanceof ExceptionThrower)) {
return false;
}
if (ins instanceof NEW) {
return false;
}
// if (ins instanceof ATHROW) return false;
if (ins instanceof GETSTATIC) {
return false;
}
if (ins instanceof PUTSTATIC) {
return false;
}
if (ins instanceof ReturnInstruction) {
return false;
}
if (ins instanceof INSTANCEOF) {
return false;
}
if (ins instanceof MONITOREXIT) {
return false;
}
if (ins instanceof LDC) {
return false;
}
if (ins instanceof GETFIELD && !methodGen.isStatic()) {
// replacedume that GETFIELD on this object is not PEI
return !isSafeFieldSource(handle.getPrev());
}
if (ins instanceof PUTFIELD && !methodGen.isStatic()) {
// replacedume that PUTFIELD on this object is not PEI
int depth = ins.consumeStack(cpg);
for (InstructionHandle prev = handle.getPrev(); prev != null; prev = prev.getPrev()) {
Instruction prevInst = prev.getInstruction();
if (prevInst instanceof BranchInstruction) {
if (prevInst instanceof GotoInstruction) {
// Currently we support only jumps to the PUTFIELD itself
// This will cover simple cases like this.a = flag ? foo : bar
if (((BranchInstruction) prevInst).getTarget() == handle) {
depth = ins.consumeStack(cpg);
} else {
return true;
}
} else if (!(prevInst instanceof IfInstruction)) {
// As IF instructions may fall through then the stack depth remains unchanged
// Actually we should not go here for normal Java bytecode: switch or jsr should not appear in this context
return true;
}
}
depth = depth - prevInst.produceStack(cpg) + prevInst.consumeStack(cpg);
if (depth < 1) {
throw new CFGBuilderException("Invalid stack at " + prev + " when checking " + handle);
}
if (depth == 1) {
InstructionHandle prevPrev = prev.getPrev();
if (prevPrev != null && prevPrev.getInstruction() instanceof BranchInstruction) {
continue;
}
return !isSafeFieldSource(prevPrev);
}
}
}
return true;
}
/**
* @param handle instruction handle which loads the object for further GETFIELD/PUTFIELD operation
* @return true if this object is known to be non-null
*/
private boolean isSafeFieldSource(InstructionHandle handle) {
while (handle != null && handle.getInstruction().getOpcode() == Const.DUP) {
// Some compilers generate DUP for field increment code like
// ALOAD_0 / DUP / GETFIELD x / ICONST_1 / IADD / PUTFIELD x
handle = handle.getPrev();
}
if (handle == null) {
return false;
}
Instruction inst = handle.getInstruction();
if (inst.getOpcode() == Const.ALOAD_0) {
return true;
}
return inst instanceof GETFIELD && ((GETFIELD) inst).getFieldName(cpg).startsWith("this$");
}
/**
* Determine whether or not the given instruction is a control flow merge.
*
* @param handle
* the instruction
* @return true if the instruction is a control merge, false otherwise
*/
private static boolean isMerge(InstructionHandle handle) {
if (handle.hasTargeters()) {
// Check all targeters of this handle to see if any
// of them are branches. If so, the instruction is a merge.
InstructionTargeter[] targeterList = handle.getTargeters();
for (InstructionTargeter targeter : targeterList) {
if (targeter instanceof BranchInstruction) {
return true;
}
}
}
return false;
}
/**
* Inline all JSR subroutines into the top-level subroutine. This produces a
* complete CFG for the entire method, in which all JSR subroutines are
* inlined.
*
* @return the CFG for the method
*/
private CFG inlineAll() throws CFGBuilderException {
CFG result = new CFG();
Context rootContext = new Context(null, topLevelSubroutine, result);
rootContext.mapBlock(topLevelSubroutine.getEntry(), result.getEntry());
rootContext.mapBlock(topLevelSubroutine.getExit(), result.getExit());
BasicBlock resultStartBlock = rootContext.getBlock(topLevelSubroutine.getStartBlock());
result.createEdge(result.getEntry(), resultStartBlock, START_EDGE);
inline(rootContext);
return result;
}
/**
* Inline a subroutine into a calling context.
*
* @param context
* the Context
*/
public void inline(Context context) throws CFGBuilderException {
CFG result = context.getResult();
// Check to ensure we're not trying to inline something that is
// recursive
context.checkForRecursion();
Subroutine subroutine = context.getSubroutine();
CFG subCFG = subroutine.getCFG();
while (context.hasMoreWork()) {
BasicBlock subBlock = context.nexreplacedem();
BasicBlock resultBlock = context.getBlock(subBlock);
// Mark blocks which are in JSR subroutines
resultBlock.setInJSRSubroutine(context.getCaller() != null);
// Copy instructions into the result block
BasicBlock.InstructionIterator insIter = subBlock.instructionIterator();
while (insIter.hasNext()) {
InstructionHandle handle = insIter.next();
resultBlock.addInstruction(handle);
}
// Set exception thrower status
if (subBlock.isExceptionThrower()) {
resultBlock.setExceptionThrower(subBlock.getExceptionThrower());
}
// Set exception handler status
if (subBlock.isExceptionHandler()) {
resultBlock.setExceptionGen(null, subBlock.getExceptionGen());
}
// Add control edges (including inlining JSR subroutines)
Iterator<Edge> edgeIter = subCFG.outgoingEdgeIterator(subBlock);
while (edgeIter.hasNext()) {
Edge edge = edgeIter.next();
int edgeType = edge.getType();
if (edgeType == JSR_EDGE) {
// Inline a JSR subroutine...
// Create a new Context
InstructionHandle jsrHandle = subBlock.getLastInstruction();
JsrInstruction jsr = (JsrInstruction) jsrHandle.getInstruction();
Subroutine jsrSub = jsrSubroutineMap.get(jsr.getTarget());
Context jsrContext = new Context(context, jsrSub, context.getResult());
// The start block in the JSR subroutine maps to the first
// inlined block in the result CFG.
BasicBlock resultJSRStartBlock = jsrContext.getBlock(jsrSub.getStartBlock());
result.createEdge(resultBlock, resultJSRStartBlock, GOTO_EDGE);
// The exit block in the JSR subroutine maps to the result
// block
// corresponding to the instruction following the JSR.
// (I.e., that is where control returns after the execution
// of
// the JSR subroutine.)
BasicBlock subJSRSuccessorBlock = subroutine.getBlock(jsrHandle.getNext());
BasicBlock resultJSRSuccessorBlock = context.getBlock(subJSRSuccessorBlock);
jsrContext.mapBlock(jsrSub.getExit(), resultJSRSuccessorBlock);
// Inline the JSR subroutine
inline(jsrContext);
} else {
// Ordinary control edge
BasicBlock resultTarget = context.getBlock(edge.getTarget());
result.createEdge(resultBlock, resultTarget, edge.getType());
}
}
// Add control edges for escape targets
Iterator<EscapeTarget> escapeTargereplaceder = subroutine.escapeTargereplacederator(subBlock);
while (escapeTargereplaceder.hasNext()) {
EscapeTarget escapeTarget = escapeTargereplaceder.next();
InstructionHandle targetInstruction = escapeTarget.getTarget();
// Look for the calling context which has the target instruction
Context caller = context.getCaller();
while (caller != null) {
if (caller.getSubroutine().containsInstruction(targetInstruction)) {
break;
}
caller = caller.getCaller();
}
if (caller == null) {
throw new CFGBuilderException("Unknown caller for escape target " + targetInstruction + " referenced by " + context.getSubroutine().getStartInstruction());
}
// Find result block in caller
BasicBlock subCallerTargetBlock = caller.getSubroutine().getBlock(targetInstruction);
BasicBlock resultCallerTargetBlock = caller.getBlock(subCallerTargetBlock);
// Add an edge to caller context
result.createEdge(resultBlock, resultCallerTargetBlock, escapeTarget.getEdgeType());
}
// If the block returns from the method, add a return edge
if (subroutine.isReturnBlock(subBlock)) {
result.createEdge(resultBlock, result.getExit(), RETURN_EDGE);
}
// If the block calls System.exit(), add an exit edge
if (subroutine.isExitBlock(subBlock)) {
result.createEdge(resultBlock, result.getExit(), EXIT_EDGE);
}
// If the block throws an unhandled exception, add an unhandled
// exception edge
if (subroutine.isUnhandledExceptionBlock(subBlock)) {
result.createEdge(resultBlock, result.getExit(), UNHANDLED_EXCEPTION_EDGE);
}
}
/*
* while (blocks are left) {
*
* get block from subroutine get corresponding block from result copy
* instructions into result block
*
* if (block terminated by JSR) { get JSR subroutine create new context
* create GOTO edge from current result block to start block of new
* inlined context map subroutine exit block to result JSR successor
* block inline (new context, result) } else { for each outgoing edge {
* map each target to result blocks (add block to to work list if
* needed) add edges to result }
*
* for each outgoing escape target { add edges into blocks in outer
* contexts (adding those blocks to outer work list if needed) }
*
* if (block returns) { add return edge from result block to result CFG
* exit block }
*
* if (block calls System.exit()) { add exit edge from result block to
* result CFG exit block }
*
* if (block throws unhandled exception) { add unhandled exception edge
* from result block to result CFG exit block } }
*
* }
*/
}
/**
* Test driver.
*/
public static void main(String[] argv) throws Exception {
if (argv.length != 1) {
System.err.println("Usage: " + BetterCFGBuilder2.clreplaced.getName() + " <clreplaced file>");
System.exit(1);
}
String methodName = SystemProperties.getProperty("cfgbuilder.method");
JavaClreplaced jclreplaced = new ClreplacedParser(argv[0]).parse();
ClreplacedGen clreplacedGen = new ClreplacedGen(jclreplaced);
Method[] methodList = jclreplaced.getMethods();
for (Method method : methodList) {
if (method.isAbstract() || method.isNative()) {
continue;
}
if (methodName != null && !method.getName().equals(methodName)) {
continue;
}
MethodDescriptor descriptor = DescriptorFactory.instance().getMethodDescriptor(jclreplaced, method);
MethodGen methodGen = new MethodGen(method, jclreplaced.getClreplacedName(), clreplacedGen.getConstantPool());
CFGBuilder cfgBuilder = new BetterCFGBuilder2(descriptor, methodGen);
cfgBuilder.build();
CFG cfg = cfgBuilder.getCFG();
CFGPrinter cfgPrinter = new CFGPrinter(cfg);
System.out.println("---------------------------------------------------------------------");
System.out.println("Method: " + SignatureConverter.convertMethodSignature(methodGen));
System.out.println("---------------------------------------------------------------------");
cfgPrinter.print(System.out);
}
}
}
19
Source : TaintDataflowEngine.java
with GNU Lesser General Public License v3.0
from blackarbiter
with GNU Lesser General Public License v3.0
from blackarbiter
private static String getSlashedMethodName(MethodGen methodGen) {
String methodNameWithSignature = methodGen.getName() + methodGen.getSignature();
String slashedClreplacedName = methodGen.getClreplacedName().replace('.', '/');
return slashedClreplacedName + "." + methodNameWithSignature;
}
19
Source : TaintAnalysis.java
with GNU Lesser General Public License v3.0
from blackarbiter
with GNU Lesser General Public License v3.0
from blackarbiter
/**
* Implements taint dataflow operations, in particular meeting facts, transfer
* function is delegated to {@link TaintFrameModelingVisitor}
*
* @author David Formanek (Y Soft Corporation, a.s.)
*/
public clreplaced Taintreplacedysis extends FrameDataflowreplacedysis<Taint, TaintFrame> {
private final MethodGen methodGen;
private final MethodInfo methodDescriptor;
private final TaintFrameModelingVisitor visitor;
private int parameterStackSize;
private List<Integer> slotToParameter;
private static final List<String> TAINTED_ANNOTATIONS = loadFileContent("taint-config/taint-param-annotations.txt");
/**
* Constructs replacedysis for the given method
*
* @param methodGen method to replacedyze
* @param dfs DFS algorithm
* @param descriptor descriptor of the method to replacedyze
* @param taintConfig configured and derived taint summaries
*/
public Taintreplacedysis(MethodGen methodGen, DepthFirstSearch dfs, MethodDescriptor descriptor, TaintConfig taintConfig) {
super(dfs);
this.methodGen = methodGen;
this.methodDescriptor = (MethodInfo) descriptor;
this.visitor = new TaintFrameModelingVisitor(methodGen.getConstantPool(), descriptor, taintConfig);
computeParametersInfo(descriptor.getSignature(), descriptor.isStatic());
}
@Override
protected void mergeValues(TaintFrame frame, TaintFrame result, int i) throws DataflowreplacedysisException {
result.setValue(i, Taint.merge(result.getValue(i), frame.getValue(i)));
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock block, TaintFrame fact) throws DataflowreplacedysisException {
visitor.setFrameAndLocation(fact, new Location(handle, block));
visitor.replacedyzeInstruction(handle.getInstruction());
}
@Override
public TaintFrame createFact() {
return new TaintFrame(methodGen.getMaxLocals());
}
/**
* Initialize the initial state of a TaintFrame.
* @param fact Initial frame
*/
@Override
public void initEntryFact(TaintFrame fact) {
fact.setValid();
fact.clearStack();
boolean inMainMethod = isInMainMethod();
int numSlots = fact.getNumSlots();
int numLocals = fact.getNumLocals();
for (int i = 0; i < numSlots; ++i) {
Taint value = new Taint(Taint.State.UNKNOWN);
if (i < numLocals) {
if (i < parameterStackSize) {
if (isTaintedByAnnotation(i - 1)) {
value = new Taint(Taint.State.TAINTED);
// this would add line number for the first instruction in the method
// value.addLocation(new TaintLocation(methodDescriptor, 0), true);
} else if (inMainMethod) {
if (FindSecBugsGlobalConfig.getInstance().isTaintedMainArgument()) {
value = new Taint(Taint.State.TAINTED);
} else {
value = new Taint(Taint.State.SAFE);
}
} else {
int stackOffset = parameterStackSize - i - 1;
value.addParameter(stackOffset);
}
}
value.setVariableIndex(i);
}
fact.setValue(i, value);
}
}
/**
* @return true if the method is the startup point of a console or gui application
* ("public static void main(String[] args)"), false otherwise
*/
private boolean isInMainMethod() {
return methodDescriptor.isStatic() && "main".equals(methodDescriptor.getName()) && "([Ljava/lang/String;)V".equals(methodDescriptor.getSignature()) && methodGen.getMethod().isPublic();
}
/**
* 添加注解是否被污染
* Determine if the slot value is tainted based on added framework annotations.
* <hr/>
* Example of mapping done:<br/>
*
* Method replacedyzed: "test(String,String,double)V"
* For the slot no 2, it look at annotations on the parameter 2.
* <pre>
* 0 1 2 3
* +++++++++++++
* [ double param3 | double param3 | String param2 | String param1 ]
* </pre>
* <br/>
* (Reminder : double and long take two slots for one parameter)
*
* @param slotNo
* @return
*/
private boolean isTaintedByAnnotation(int slotNo) {
if (slotNo >= 0 && methodDescriptor.hasParameterAnnotations()) {
int parameter = slotToParameter.get(slotNo);
Collection<AnnotationValue> annotations = methodDescriptor.getParameterAnnotations(parameter);
for (AnnotationValue annotation : annotations) {
if (TAINTED_ANNOTATIONS.contains(annotation.getAnnotationClreplaced().getClreplacedName())) {
return true;
}
}
}
return false;
}
@Override
public void meetInto(TaintFrame fact, Edge edge, TaintFrame result) throws DataflowreplacedysisException {
if (fact.isValid() && edge.isExceptionEdge()) {
TaintFrame copy = null;
// creates modifiable copy
copy = modifyFrame(fact, copy);
copy.clearStack();
// do not trust values that are safe just when an exception occurs
copy.pushValue(new Taint(Taint.State.UNKNOWN));
fact = copy;
}
mergeInto(fact, result);
}
/**
* This method must be called after executing the data flow
*/
public void finishreplacedysis() {
visitor.finishreplacedysis();
}
/**
* Compute two values:
* <li>The number of values required on the stack for a specific call.</li>
* <li>The parameter replacedociation with each slot.</li>
*
* <hr/>
*
* For exemple : "(I[Ljava/lang/String;Ljava/lang/Object;)V" => void a(Integer, String, Object)<br/><br/>
* Expected Stack prior the method invocation :<br/>
* <pre>
* +--------------+
* | 0: Object |
* +--------------+
* | 1: String |
* +--------------+
* | 2: int |
* +--------------+
* </pre>
* <hr/>
*
* Special note: double and long (primitive types) value take two slots.<br/>
* For exemple : "(IDJ)V" => void a(Integer, Double, Long)
* <pre>
* +--------------+
* | 0: long pt1 |
* +--------------+
* | 1: long pt2 |
* +--------------+
* | 2: double pt1|
* +--------------+
* | 3: double pt2|
* +--------------+
* | 4: int |
* +--------------+
* </pre>
*
* @param signature
* @param isStatic
* @return
*/
private void computeParametersInfo(String signature, boolean isStatic) {
replacedert signature != null && !signature.isEmpty();
// static methods does not have reference to this
int stackSize = isStatic ? 0 : 1;
GenericSignatureParser parser = new GenericSignatureParser(signature);
Iterator<String> iterator = parser.parameterSignatureIterator();
int paramIdx = 0;
slotToParameter = new ArrayList<Integer>();
while (iterator.hasNext()) {
String parameter = iterator.next();
if (parameter.equals("D") || parameter.equals("J")) {
// double and long types takes two slots
stackSize += 2;
slotToParameter.add(paramIdx);
slotToParameter.add(paramIdx);
} else {
stackSize++;
slotToParameter.add(paramIdx);
}
paramIdx++;
}
parameterStackSize = stackSize;
}
private static List<String> loadFileContent(String path) {
BufferedReader stream = null;
try {
InputStream in = Taintreplacedysis.clreplaced.getClreplacedLoader().getResourcereplacedtream(path);
stream = new BufferedReader(new InputStreamReader(in, "utf-8"));
String line;
List<String> content = new ArrayList<String>();
while ((line = stream.readLine()) != null) {
content.add(line.trim());
}
return content;
} catch (IOException ex) {
replacedert false : ex.getMessage();
} finally {
IO.close(stream);
}
return new ArrayList<String>();
}
}
18
Source : SourceLineAnnotation.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Factory method for creating a source line annotation describing the
* source line number for a visited instruction.
*
* @param clreplacedContext
* the ClreplacedContext
* @param methodGen
* the MethodGen object representing the method
* @param handle
* the InstructionHandle containing the visited instruction
* @return the SourceLineAnnotation, or null if we do not have line number
* information for the instruction
*/
@Nonnull
public static SourceLineAnnotation fromVisitedInstruction(ClreplacedContext clreplacedContext, MethodGen methodGen, String sourceFile, @Nonnull InstructionHandle handle) {
LineNumberTable table = methodGen.getLineNumberTable(methodGen.getConstantPool());
String clreplacedName = methodGen.getClreplacedName();
int bytecodeOffset = handle.getPosition();
if (table == null) {
return createUnknown(clreplacedName, sourceFile, bytecodeOffset, bytecodeOffset);
}
int lineNumber = table.getSourceLine(handle.getPosition());
return new SourceLineAnnotation(clreplacedName, sourceFile, lineNumber, lineNumber, bytecodeOffset, bytecodeOffset);
}
18
Source : SourceLineAnnotation.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Factory method for creating a source line annotation describing an entire
* method.
*
* @param methodGen
* the method being visited
* @return the SourceLineAnnotation, or null if we do not have line number
* information for the method
*/
public static SourceLineAnnotation fromVisitedMethod(MethodGen methodGen, String sourceFile) {
LineNumberTable lineNumberTable = methodGen.getLineNumberTable(methodGen.getConstantPool());
String clreplacedName = methodGen.getClreplacedName();
int codeSize = methodGen.getInstructionList().getLength();
if (lineNumberTable == null) {
return createUnknown(clreplacedName, sourceFile, 0, codeSize - 1);
}
return forEntireMethod(clreplacedName, sourceFile, lineNumberTable, codeSize);
}
18
Source : SourceLineAnnotation.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Factory method for creating a source line annotation describing the
* source line numbers for a range of instruction in a method.
*
* @param clreplacedContext
* theClreplacedContext
* @param methodGen
* the method
* @param start
* the start instruction
* @param end
* the end instruction (inclusive)
*/
public static SourceLineAnnotation fromVisitedInstructionRange(ClreplacedContext clreplacedContext, MethodGen methodGen, String sourceFile, InstructionHandle start, InstructionHandle end) {
LineNumberTable lineNumberTable = methodGen.getLineNumberTable(methodGen.getConstantPool());
String clreplacedName = methodGen.getClreplacedName();
if (lineNumberTable == null) {
return createUnknown(clreplacedName, sourceFile, start.getPosition(), end.getPosition());
}
int startLine = lineNumberTable.getSourceLine(start.getPosition());
int endLine = lineNumberTable.getSourceLine(end.getPosition());
return new SourceLineAnnotation(clreplacedName, sourceFile, startLine, endLine, start.getPosition(), end.getPosition());
}
18
Source : RedundantConditions.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* @param methodGen method
* @param start instruction to scan
* @return instruction which consumes value which was on top of stack before start instruction
* or null if cannot be determined
*/
private InstructionHandle getConsumer(MethodGen methodGen, InstructionHandle start) {
int depth = 1;
InstructionHandle cur = start;
while (cur != null) {
Instruction inst = cur.getInstruction();
depth -= inst.consumeStack(methodGen.getConstantPool());
if (depth <= 0) {
return cur;
}
depth += inst.produceStack(methodGen.getConstantPool());
if (inst instanceof BranchInstruction) {
if (inst instanceof GotoInstruction) {
cur = ((GotoInstruction) inst).getTarget();
continue;
}
if (!(inst instanceof IfInstruction)) {
return null;
}
}
cur = cur.getNext();
}
return null;
}
18
Source : FindSqlInjection.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
@Override
public void visitClreplacedContext(ClreplacedContext clreplacedContext) {
JavaClreplaced javaClreplaced = clreplacedContext.getJavaClreplaced();
if (!PreorderVisitor.hasInterestingMethod(javaClreplaced.getConstantPool(), allMethods)) {
return;
}
Method[] methodList = javaClreplaced.getMethods();
for (Method method : methodList) {
MethodGen methodGen = clreplacedContext.getMethodGen(method);
if (methodGen == null) {
continue;
}
try {
replacedyzeMethod(clreplacedContext, method);
} catch (DataflowreplacedysisException e) {
bugReporter.logError("FindSqlInjection caught exception while replacedyzing " + clreplacedContext.getFullyQualifiedMethodName(method), e);
} catch (CFGBuilderException e) {
bugReporter.logError("FindSqlInjection caught exception while replacedyzing " + clreplacedContext.getFullyQualifiedMethodName(method), e);
} catch (RuntimeException e) {
bugReporter.logError("FindSqlInjection caught exception while replacedyzing " + clreplacedContext.getFullyQualifiedMethodName(method), e);
}
}
}
18
Source : StoreDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public StoreDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
return null;
}
Storereplacedysis replacedysis = new Storereplacedysis(getDepthFirstSearch(replacedysisCache, descriptor), getConstantPoolGen(replacedysisCache, descriptor.getClreplacedDescriptor()));
StoreDataflow dataflow = new StoreDataflow(getCFG(replacedysisCache, descriptor), replacedysis);
dataflow.execute();
return dataflow;
}
18
Source : LoadDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public LoadDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
return null;
}
Loadreplacedysis replacedysis = new Loadreplacedysis(getDepthFirstSearch(replacedysisCache, descriptor), getConstantPoolGen(replacedysisCache, descriptor.getClreplacedDescriptor()));
LoadDataflow dataflow = new LoadDataflow(getCFG(replacedysisCache, descriptor), replacedysis);
dataflow.execute();
return dataflow;
}
18
Source : ConstantDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public ConstantDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
return null;
}
Constantreplacedysis replacedysis = new Constantreplacedysis(methodGen, getDepthFirstSearch(replacedysisCache, descriptor));
ConstantDataflow dataflow = new ConstantDataflow(getCFG(replacedysisCache, descriptor), replacedysis);
dataflow.execute();
return dataflow;
}
18
Source : TypeAnalysis.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* <p>A forward dataflow replacedysis to determine the types of all values in the Java
* stack frame at all points in a Java method. The values include local
* variables and values on the Java operand stack.
* </p>
* <p>
* As a side effect, the replacedysis computes the exception set throwable on each
* exception edge in the CFG. This information can be used to prune infeasible
* exception edges, and mark exception edges which propagate only implicit
* exceptions.</p>
*
* @author David Hovemeyer
* @see Dataflow
* @see edu.umd.cs.findbugs.ba.Dataflowreplacedysis
* @see TypeFrame
*/
public clreplaced Typereplacedysis extends FrameDataflowreplacedysis<Type, TypeFrame> implements EdgeTypes {
public static final boolean DEBUG = SystemProperties.getBoolean("ta.debug");
/**
* Force computation of accurate exceptions.
*/
public static final boolean FORCE_ACCURATE_EXCEPTIONS = SystemProperties.getBoolean("ta.accurateExceptions");
/**
* Repository of information about thrown exceptions computed for a basic
* block and its outgoing exception edges. It contains a result TypeFrame,
* which is used to detect when the exception information needs to be
* recomputed for the block.
*/
private clreplaced CachedExceptionSet {
private final TypeFrame result;
private final ExceptionSet exceptionSet;
private final Map<Edge, ExceptionSet> edgeExceptionMap;
public CachedExceptionSet(TypeFrame result, ExceptionSet exceptionSet) {
this.result = result;
this.exceptionSet = exceptionSet;
this.edgeExceptionMap = new HashMap<>();
}
public boolean isUpToDate(TypeFrame result) {
return this.result.equals(result);
}
public ExceptionSet getExceptionSet() {
return exceptionSet;
}
public void setEdgeExceptionSet(Edge edge, ExceptionSet exceptionSet) {
edgeExceptionMap.put(edge, exceptionSet);
}
public ExceptionSet getEdgeExceptionSet(Edge edge) {
ExceptionSet edgeExceptionSet = edgeExceptionMap.get(edge);
if (edgeExceptionSet == null) {
edgeExceptionSet = exceptionSetFactory.createExceptionSet();
edgeExceptionMap.put(edge, edgeExceptionSet);
}
return edgeExceptionSet;
}
}
/**
* Cached information about an instanceof check.
*/
static clreplaced InstanceOfCheck {
final ValueNumber valueNumber;
final Type type;
InstanceOfCheck(ValueNumber valueNumber, Type type) {
this.valueNumber = valueNumber;
this.type = type;
}
/**
* @return Returns the valueNumber.
*/
public ValueNumber getValueNumber() {
return valueNumber;
}
/**
* @return Returns the type.
*/
public Type getType() {
return type;
}
}
protected MethodGen methodGen;
private final Method method;
protected CFG cfg;
private final TypeMerger typeMerger;
private final TypeFrameModelingVisitor visitor;
private final Map<BasicBlock, CachedExceptionSet> thrownExceptionSetMap;
private final RepositoryLookupFailureCallback lookupFailureCallback;
private final ExceptionSetFactory exceptionSetFactory;
private ValueNumberDataflow valueNumberDataflow;
private final Map<BasicBlock, InstanceOfCheck> instanceOfCheckMap;
/**
* Constructor.
*
* @param method
* TODO
* @param methodGen
* the MethodGen whose CFG we'll be replacedyzing
* @param cfg
* the control flow graph
* @param dfs
* DepthFirstSearch of the method
* @param typeMerger
* object to merge types
* @param visitor
* a TypeFrameModelingVisitor to use to model the effect of
* instructions
* @param lookupFailureCallback
* lookup failure callback
* @param exceptionSetFactory
* factory for creating ExceptionSet objects
*/
public Typereplacedysis(Method method, MethodGen methodGen, CFG cfg, DepthFirstSearch dfs, TypeMerger typeMerger, TypeFrameModelingVisitor visitor, RepositoryLookupFailureCallback lookupFailureCallback, ExceptionSetFactory exceptionSetFactory) {
super(dfs);
this.method = method;
Code code = method.getCode();
if (code == null) {
throw new IllegalArgumentException(method.getName() + " has no code");
}
for (Attribute a : code.getAttributes()) {
if (a instanceof LocalVariableTypeTable) {
visitor.setLocalTypeTable((LocalVariableTypeTable) a);
}
}
this.methodGen = methodGen;
this.cfg = cfg;
this.typeMerger = typeMerger;
this.visitor = visitor;
this.thrownExceptionSetMap = new HashMap<>();
this.lookupFailureCallback = lookupFailureCallback;
this.exceptionSetFactory = exceptionSetFactory;
this.instanceOfCheckMap = new HashMap<>();
if (DEBUG) {
System.out.println("\n\nreplacedyzing " + methodGen);
}
}
/**
* Constructor.
*
* @param method
* TODO
* @param methodGen
* the MethodGen whose CFG we'll be replacedyzing
* @param cfg
* the control flow graph
* @param dfs
* DepthFirstSearch of the method
* @param typeMerger
* object to merge types
* @param lookupFailureCallback
* lookup failure callback
* @param exceptionSetFactory
* factory for creating ExceptionSet objects
*/
public Typereplacedysis(Method method, MethodGen methodGen, CFG cfg, DepthFirstSearch dfs, TypeMerger typeMerger, RepositoryLookupFailureCallback lookupFailureCallback, ExceptionSetFactory exceptionSetFactory) {
this(method, methodGen, cfg, dfs, typeMerger, new TypeFrameModelingVisitor(methodGen.getConstantPool(), typeMerger), lookupFailureCallback, exceptionSetFactory);
if (TypeFrameModelingVisitor.DEBUG) {
System.out.println(methodGen.getClreplacedName() + "." + methodGen.getName() + " " + methodGen.getSignature());
}
}
/**
* Constructor which uses StandardTypeMerger.
*
* @param method
* TODO
* @param methodGen
* the MethodGen whose CFG we'll be replacedyzing
* @param cfg
* the control flow graph
* @param dfs
* DepthFirstSearch of the method
* @param lookupFailureCallback
* callback for Repository lookup failures
* @param exceptionSetFactory
* factory for creating ExceptionSet objects
*/
public Typereplacedysis(Method method, MethodGen methodGen, CFG cfg, DepthFirstSearch dfs, RepositoryLookupFailureCallback lookupFailureCallback, ExceptionSetFactory exceptionSetFactory) {
this(method, methodGen, cfg, dfs, new StandardTypeMerger(lookupFailureCallback, exceptionSetFactory), lookupFailureCallback, exceptionSetFactory);
}
/**
* Set the ValueNumberDataflow for the method being replacedyzed. This is
* optional; if set, it will be used to make instanceof instructions more
* precise.
*
* @param valueNumberDataflow
* the ValueNumberDataflow
*/
public void setValueNumberDataflow(ValueNumberDataflow valueNumberDataflow) {
this.valueNumberDataflow = valueNumberDataflow;
this.visitor.setValueNumberDataflow(valueNumberDataflow);
}
/**
* Set the FieldStoreTypeDatabase. This can be used to get more accurate
* types for values loaded from fields.
*
* @param database
* the FieldStoreTypeDatabase
*/
public void setFieldStoreTypeDatabase(FieldStoreTypeDatabase database) {
visitor.setFieldStoreTypeDatabase(database);
}
/**
* Get the set of exceptions that can be thrown on given edge. This should
* only be called after the replacedysis completes.
*
* @param edge
* the Edge
* @return the ExceptionSet
*/
public ExceptionSet getEdgeExceptionSet(Edge edge) {
CachedExceptionSet cachedExceptionSet = thrownExceptionSetMap.get(edge.getSource());
return cachedExceptionSet.getEdgeExceptionSet(edge);
}
@Override
public TypeFrame createFact() {
return new TypeFrame(methodGen.getMaxLocals());
}
@Override
public void initEntryFact(TypeFrame result) {
// Make the frame valid
result.setValid();
int slot = 0;
// Clear the stack slots in the frame
result.clearStack();
// Add local for "this" pointer, if present
if (!methodGen.isStatic()) {
result.setValue(slot++, ObjectTypeFactory.getInstance(methodGen.getClreplacedName()));
}
// [Added: Support for Generics]
// Get a parser that reads the generic signature of the method and
// can be used to get the correct GenericObjectType if an argument
// has a clreplaced type
Iterator<String> iter = GenericSignatureParser.getGenericSignatureIterator(method);
// Add locals for parameters.
// Note that long and double parameters need to be handled
// specially because they occupy two locals.
Type[] argumentTypes = methodGen.getArgumentTypes();
for (Type argType : argumentTypes) {
// Add special "extra" type for long or double params.
// These occupy the slot before the "plain" type.
if (argType.getType() == Const.T_LONG) {
result.setValue(slot++, TypeFrame.getLongExtraType());
} else if (argType.getType() == Const.T_DOUBLE) {
result.setValue(slot++, TypeFrame.getDoubleExtraType());
}
// [Added: Support for Generics]
String s = (iter == null || !iter.hasNext()) ? null : iter.next();
if (s != null && (argType instanceof ObjectType || argType instanceof ArrayType) && !(argType instanceof ExceptionObjectType)) {
// replace with a generic version of the type
try {
Type t = GenericUtilities.getType(s);
if (t != null) {
argType = t;
}
} catch (RuntimeException e) {
}
// degrade gracefully
}
// Add the plain parameter type.
result.setValue(slot++, argType);
}
// Set remaining locals to BOTTOM; this will cause any
// uses of them to be flagged
while (slot < methodGen.getMaxLocals()) {
result.setValue(slot++, TypeFrame.getBottomType());
}
}
@Override
public void copy(TypeFrame source, TypeFrame dest) {
dest.copyFrom(source);
}
@Override
public void makeFactTop(TypeFrame fact) {
fact.setTop();
}
@Override
public boolean isFactValid(TypeFrame fact) {
return fact.isValid();
}
@Override
public boolean same(TypeFrame fact1, TypeFrame fact2) {
return fact1.sameAs(fact2);
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, TypeFrame fact) throws DataflowreplacedysisException {
visitor.setFrameAndLocation(fact, new Location(handle, basicBlock));
visitor.replacedyzeInstruction(handle.getInstruction());
}
@Override
public void transfer(BasicBlock basicBlock, @CheckForNull InstructionHandle end, TypeFrame start, TypeFrame result) throws DataflowreplacedysisException {
visitor.startBasicBlock();
super.transfer(basicBlock, end, start, result);
// Compute thrown exception types
computeThrownExceptionTypes(basicBlock, end, result);
if (DEBUG) {
System.out.println("After " + basicBlock.getFirstInstruction() + " -> " + basicBlock.getLastInstruction());
System.out.println(" frame: " + result);
}
// If this block ends with an instanceof check,
// update the cached information about it.
instanceOfCheckMap.remove(basicBlock);
if (visitor.isInstanceOfFollowedByBranch()) {
InstanceOfCheck check = new InstanceOfCheck(visitor.getInstanceOfValueNumber(), visitor.getInstanceOfType());
instanceOfCheckMap.put(basicBlock, check);
}
}
private void computeThrownExceptionTypes(BasicBlock basicBlock, @CheckForNull InstructionHandle end, TypeFrame result) throws DataflowreplacedysisException {
// Do nothing if we're not computing propagated exceptions
if (!(FORCE_ACCURATE_EXCEPTIONS || replacedysisContext.currentreplacedysisContext().getBoolProperty(replacedysisFeatures.ACCURATE_EXCEPTIONS))) {
return;
}
// Also, nothing to do if the block is not an exception thrower
if (!basicBlock.isExceptionThrower()) {
return;
}
// If cached results are up to date, don't recompute.
CachedExceptionSet cachedExceptionSet = getCachedExceptionSet(basicBlock);
if (cachedExceptionSet.isUpToDate(result)) {
return;
}
// Figure out what exceptions can be thrown out
// of the basic block, and mark each exception edge
// with the set of exceptions which can be propagated
// along the edge.
int exceptionEdgeCount = 0;
Edge lastExceptionEdge = null;
for (Iterator<Edge> i = cfg.outgoingEdgeIterator(basicBlock); i.hasNext(); ) {
Edge e = i.next();
if (e.isExceptionEdge()) {
exceptionEdgeCount++;
lastExceptionEdge = e;
}
}
if (exceptionEdgeCount == 0) {
// System.out.println("Shouldn't all blocks have an exception edge");
return;
}
// Compute exceptions that can be thrown by the
// basic block.
cachedExceptionSet = computeBlockExceptionSet(basicBlock, result);
if (exceptionEdgeCount == 1) {
cachedExceptionSet.setEdgeExceptionSet(lastExceptionEdge, cachedExceptionSet.getExceptionSet());
return;
}
// For each outgoing exception edge, compute exceptions
// that can be thrown. This replacedumes that the exception
// edges are enumerated in decreasing order of priority.
// In the process, this will remove exceptions from
// the thrown exception set.
ExceptionSet thrownExceptionSet = cachedExceptionSet.getExceptionSet();
if (!thrownExceptionSet.isEmpty()) {
thrownExceptionSet = thrownExceptionSet.duplicate();
}
for (Iterator<Edge> i = cfg.outgoingEdgeIterator(basicBlock); i.hasNext(); ) {
Edge edge = i.next();
if (edge.isExceptionEdge()) {
cachedExceptionSet.setEdgeExceptionSet(edge, computeEdgeExceptionSet(edge, thrownExceptionSet));
}
}
}
@Override
public void meetInto(TypeFrame fact, Edge edge, TypeFrame result) throws DataflowreplacedysisException {
BasicBlock basicBlock = edge.getTarget();
if (fact.isValid()) {
TypeFrame tmpFact = null;
// Handling an exception?
if (basicBlock.isExceptionHandler()) {
tmpFact = modifyFrame(fact, null);
// Special case: when merging predecessor facts for entry to
// an exception handler, we clear the stack and push a
// single entry for the exception object. That way, the locals
// can still be merged.
CodeExceptionGen exceptionGen = basicBlock.getExceptionGen();
tmpFact.clearStack();
// Determine the type of exception(s) caught.
Type catchType = null;
if (FORCE_ACCURATE_EXCEPTIONS || replacedysisContext.currentreplacedysisContext().getBoolProperty(replacedysisFeatures.ACCURATE_EXCEPTIONS)) {
try {
// Ideally, the exceptions that can be propagated
// on this edge has already been computed.
CachedExceptionSet cachedExceptionSet = getCachedExceptionSet(edge.getSource());
ExceptionSet edgeExceptionSet = cachedExceptionSet.getEdgeExceptionSet(edge);
if (!edgeExceptionSet.isEmpty()) {
// System.out.println("Using computed edge exception set!");
catchType = ExceptionObjectType.fromExceptionSet(edgeExceptionSet);
}
} catch (ClreplacedNotFoundException e) {
lookupFailureCallback.reportMissingClreplaced(e);
}
}
if (catchType == null) {
// No information about propagated exceptions, so
// pick a type conservatively using the handler catch type.
catchType = exceptionGen.getCatchType();
if (catchType == null) {
// handle catches anything
catchType = Type.THROWABLE;
// throwable
}
}
tmpFact.pushValue(catchType);
}
// See if we can make some types more precise due to
// a successful instanceof check in the source block.
if (valueNumberDataflow != null) {
tmpFact = handleInstanceOfBranch(fact, tmpFact, edge);
}
if (tmpFact != null) {
fact = tmpFact;
}
}
mergeInto(fact, result);
}
private TypeFrame handleInstanceOfBranch(TypeFrame fact, TypeFrame tmpFact, Edge edge) {
InstanceOfCheck check = instanceOfCheckMap.get(edge.getSource());
if (check == null) {
// System.out.println("no instanceof check for block " +
// edge.getSource().getId());
return tmpFact;
}
if (check.getValueNumber() == null) {
// System.out.println("instanceof check for block " +
// edge.getSource().getId() + " has no value number");
return tmpFact;
}
ValueNumber instanceOfValueNumber = check.getValueNumber();
ValueNumberFrame vnaFrame = valueNumberDataflow.getStartFact(edge.getTarget());
if (!vnaFrame.isValid()) {
return tmpFact;
}
Type instanceOfType = check.getType();
if (!(instanceOfType instanceof ReferenceType)) {
return tmpFact;
}
short branchOpcode = edge.getSource().getLastInstruction().getInstruction().getOpcode();
int edgeType = edge.getType();
int numSlots = Math.min(fact.getNumSlots(), vnaFrame.getNumSlots());
if ((edgeType == EdgeTypes.IFCMP_EDGE && (branchOpcode == Const.IFNE || branchOpcode == Const.IFGT || branchOpcode == Const.IFNULL)) || (edgeType == EdgeTypes.FALL_THROUGH_EDGE && (branchOpcode == Const.IFEQ || branchOpcode == Const.IFLE || branchOpcode == Const.IFNONNULL))) {
// System.out.println("Successful check on edge " + edge);
// Successful instanceof check.
for (int i = 0; i < numSlots; ++i) {
if (!vnaFrame.getValue(i).equals(instanceOfValueNumber)) {
continue;
}
Type checkedType = fact.getValue(i);
if (!(checkedType instanceof ReferenceType)) {
continue;
}
// Only refine the type if the cast is feasible: i.e., a
// downcast.
// Otherwise, just set it to TOP.
try {
boolean guaranteed = Hierarchy.isSubtype((ReferenceType) checkedType, (ReferenceType) instanceOfType);
if (guaranteed) {
continue;
}
boolean feasibleCheck = instanceOfType.equals(NullType.instance()) || Hierarchy.isSubtype((ReferenceType) instanceOfType, (ReferenceType) checkedType);
if (!feasibleCheck && instanceOfType instanceof ObjectType && checkedType instanceof ObjectType) {
double v = replacedyze.deepInstanceOf(((ObjectType) instanceOfType).getClreplacedName(), ((ObjectType) checkedType).getClreplacedName());
if (v > 0.0) {
feasibleCheck = true;
}
}
tmpFact = modifyFrame(fact, tmpFact);
if (feasibleCheck) {
tmpFact.setValue(i, instanceOfType);
} else {
tmpFact.setTop();
return tmpFact;
}
} catch (ClreplacedNotFoundException e) {
lookupFailureCallback.reportMissingClreplaced(e);
return tmpFact;
}
}
} else if (!instanceOfType.equals(NullType.instance())) {
for (int i = 0; i < numSlots; ++i) {
if (!vnaFrame.getValue(i).equals(instanceOfValueNumber)) {
continue;
}
Type checkedType = fact.getValue(i);
if (!(checkedType instanceof ReferenceType)) {
continue;
}
try {
boolean guaranteed = Hierarchy.isSubtype((ReferenceType) checkedType, (ReferenceType) instanceOfType);
if (!guaranteed) {
continue;
}
tmpFact = modifyFrame(fact, tmpFact);
tmpFact.setTop();
return tmpFact;
} catch (ClreplacedNotFoundException e) {
lookupFailureCallback.reportMissingClreplaced(e);
return tmpFact;
}
}
}
return tmpFact;
}
@Override
protected void mergeValues(TypeFrame otherFrame, TypeFrame resultFrame, int slot) throws DataflowreplacedysisException {
Type type2 = resultFrame.getValue(slot);
Type type1 = otherFrame.getValue(slot);
Type value = typeMerger.mergeTypes(type2, type1);
resultFrame.setValue(slot, value);
// Result type is exact IFF types are identical and both are exact
boolean typesAreIdentical = type1.equals(type2);
boolean bothExact = resultFrame.isExact(slot) && otherFrame.isExact(slot);
resultFrame.setExact(slot, typesAreIdentical && bothExact);
}
/**
* Get the cached set of exceptions that can be thrown from given basic
* block. If this information hasn't been computed yet, then an empty
* exception set is returned.
*
* @param basicBlock
* the block to get the cached exception set for
* @return the CachedExceptionSet for the block
*/
private CachedExceptionSet getCachedExceptionSet(BasicBlock basicBlock) {
CachedExceptionSet cachedExceptionSet = thrownExceptionSetMap.get(basicBlock);
if (cachedExceptionSet == null) {
// When creating the cached exception type set for the first time:
// - the block result is set to TOP, so it won't match
// any block result that has actually been computed
// using the replacedysis transfer function
// - the exception set is created as empty (which makes it
// return TOP as its common superclreplaced)
TypeFrame top = createFact();
makeFactTop(top);
cachedExceptionSet = new CachedExceptionSet(top, exceptionSetFactory.createExceptionSet());
thrownExceptionSetMap.put(basicBlock, cachedExceptionSet);
}
return cachedExceptionSet;
}
/**
* Compute the set of exceptions that can be thrown from the given basic
* block. This should only be called if the existing cached exception set is
* out of date.
*
* @param basicBlock
* the basic block
* @param result
* the result fact for the block; this is used to determine
* whether or not the cached exception set is up to date
* @return the cached exception set for the block
*/
private CachedExceptionSet computeBlockExceptionSet(BasicBlock basicBlock, TypeFrame result) throws DataflowreplacedysisException {
ExceptionSet exceptionSet = computeThrownExceptionTypes(basicBlock);
TypeFrame copyOfResult = createFact();
copy(result, copyOfResult);
CachedExceptionSet cachedExceptionSet = new CachedExceptionSet(copyOfResult, exceptionSet);
thrownExceptionSetMap.put(basicBlock, cachedExceptionSet);
return cachedExceptionSet;
}
/**
* Based on the set of exceptions that can be thrown from the source basic
* block, compute the set of exceptions that can propagate along given
* exception edge. This method should be called for each outgoing exception
* edge in sequence, so the caught exceptions can be removed from the thrown
* exception set as needed.
*
* @param edge
* the exception edge
* @param thrownExceptionSet
* current set of exceptions that can be thrown, taking earlier
* (higher priority) exception edges into account
* @return the set of exceptions that can propagate along this edge
*/
private ExceptionSet computeEdgeExceptionSet(Edge edge, ExceptionSet thrownExceptionSet) {
if (thrownExceptionSet.isEmpty()) {
return thrownExceptionSet;
}
ExceptionSet result = exceptionSetFactory.createExceptionSet();
if (edge.getType() == UNHANDLED_EXCEPTION_EDGE) {
// The unhandled exception edge always comes
// after all of the handled exception edges.
result.addAll(thrownExceptionSet);
thrownExceptionSet.clear();
return result;
}
BasicBlock handlerBlock = edge.getTarget();
CodeExceptionGen handler = handlerBlock.getExceptionGen();
ObjectType catchType = handler.getCatchType();
if (Hierarchy.isUniversalExceptionHandler(catchType)) {
result.addAll(thrownExceptionSet);
thrownExceptionSet.clear();
} else {
// Go through the set of thrown exceptions.
// Any that will DEFINITELY be caught be this handler, remove.
// Any that MIGHT be caught, but won't definitely be caught,
// remain.
for (ExceptionSet.ThrownExceptionIterator i = thrownExceptionSet.iterator(); i.hasNext(); ) {
// ThrownException thrownException = i.next();
ObjectType thrownType = i.next();
boolean explicit = i.isExplicit();
if (DEBUG) {
System.out.println("\texception type " + thrownType + ", catch type " + catchType);
}
try {
if (Hierarchy.isSubtype(thrownType, catchType)) {
// Exception can be thrown along this edge
result.add(thrownType, explicit);
// And it will definitely be caught
i.remove();
if (DEBUG) {
System.out.println("\tException is subtype of catch type: " + "will definitely catch");
}
} else if (Hierarchy.isSubtype(catchType, thrownType)) {
// Exception possibly thrown along this edge
result.add(thrownType, explicit);
if (DEBUG) {
System.out.println("\tException is supertype of catch type: " + "might catch");
}
}
} catch (ClreplacedNotFoundException e) {
// As a special case, if a clreplaced hierarchy lookup
// fails, then we will conservatively replacedume that the
// exception in question CAN, but WON'T NECESSARILY
// be caught by the handler.
replacedysisContext.reportMissingClreplaced(e);
result.add(thrownType, explicit);
}
}
}
return result;
}
/**
* Compute the set of exception types that can be thrown by given basic
* block.
*
* @param basicBlock
* the basic block
* @return the set of exceptions that can be thrown by the block
*/
private ExceptionSet computeThrownExceptionTypes(BasicBlock basicBlock) throws DataflowreplacedysisException {
ExceptionSet exceptionTypeSet = exceptionSetFactory.createExceptionSet();
InstructionHandle pei = basicBlock.getExceptionThrower();
Instruction ins = pei.getInstruction();
// Get the exceptions that BCEL knows about.
// Note that all of these are unchecked.
ExceptionThrower exceptionThrower = (ExceptionThrower) ins;
Clreplaced<?>[] exceptionList = exceptionThrower.getExceptions();
for (Clreplaced<?> aExceptionList : exceptionList) {
exceptionTypeSet.addImplicit(ObjectTypeFactory.getInstance(aExceptionList.getName()));
}
// replacedume that an Error may be thrown by any instruction.
exceptionTypeSet.addImplicit(Hierarchy.ERROR_TYPE);
if (ins instanceof ATHROW) {
// For ATHROW instructions, we generate *two* blocks
// for which the ATHROW is an exception thrower.
//
// - The first, empty basic block, does the null check
// - The second block, which actually contains the ATHROW,
// throws the object on the top of the operand stack
//
// We make a special case of the block containing the ATHROW,
// by removing all of the implicit exceptions,
// and using type information to figure out what is thrown.
if (basicBlock.containsInstruction(pei)) {
// This is the actual ATHROW, not the null check
// and implicit exceptions.
exceptionTypeSet.clear();
// The frame containing the thrown value is the start fact
// for the block, because ATHROW is guaranteed to be
// the only instruction in the block.
TypeFrame frame = getStartFact(basicBlock);
// Check whether or not the frame is valid.
// Sun's javac sometimes emits unreachable code.
// For example, it will emit code that follows a JSR
// subroutine call that never returns.
// If the frame is invalid, then we can just make
// a conservative replacedumption that anything could be
// thrown at this ATHROW.
if (!frame.isValid()) {
exceptionTypeSet.addExplicit(Type.THROWABLE);
} else if (frame.getStackDepth() == 0) {
throw new IllegalStateException("empty stack " + " thrown by " + pei + " in " + SignatureConverter.convertMethodSignature(methodGen));
} else {
Type throwType = frame.getTopValue();
if (throwType instanceof ObjectType) {
exceptionTypeSet.addExplicit((ObjectType) throwType);
} else {
// Not sure what is being thrown here.
// Be conservative.
if (DEBUG) {
System.out.println("Non object type " + throwType + " thrown by " + pei + " in " + SignatureConverter.convertMethodSignature(methodGen));
}
exceptionTypeSet.addExplicit(Type.THROWABLE);
}
}
}
}
// If it's an InvokeInstruction, add declared exceptions and
// RuntimeException
if (ins instanceof InvokeInstruction) {
ConstantPoolGen cpg = methodGen.getConstantPool();
InvokeInstruction inv = (InvokeInstruction) ins;
ObjectType[] declaredExceptionList = Hierarchy2.findDeclaredExceptions(inv, cpg);
if (declaredExceptionList == null) {
// Couldn't find declared exceptions,
// so conservatively replacedume it could thrown any checked
// exception.
if (DEBUG) {
System.out.println("Couldn't find declared exceptions for " + SignatureConverter.convertMethodSignature(inv, cpg));
}
exceptionTypeSet.addExplicit(Hierarchy.EXCEPTION_TYPE);
} else {
for (ObjectType aDeclaredExceptionList : declaredExceptionList) {
exceptionTypeSet.addExplicit(aDeclaredExceptionList);
}
}
exceptionTypeSet.addImplicit(Hierarchy.RUNTIME_EXCEPTION_TYPE);
}
if (DEBUG) {
System.out.println(pei + " can throw " + exceptionTypeSet);
}
return exceptionTypeSet;
}
@Override
public String toString() {
return this.getClreplaced().getSimpleName() + "(" + methodGen.getClreplacedName() + "." + methodGen.getMethod().getName() + methodGen.getMethod().getSignature() + ")";
}
public boolean isImpliedByGenericTypes(ReferenceType t) {
return visitor.isImpliedByGenericTypes(t);
}
// public static void main(String[] argv) throws Exception {
// if (argv.length != 1) {
// System.err.println("Usage: " + Typereplacedysis.clreplaced.getName() +
// " <clreplaced file>");
// System.exit(1);
// }
//
// DataflowTestDriver<TypeFrame, Typereplacedysis> driver = new
// DataflowTestDriver<TypeFrame, Typereplacedysis>() {
// @Override
// public Dataflow<TypeFrame, Typereplacedysis> createDataflow(ClreplacedContext
// clreplacedContext, Method method)
// throws CFGBuilderException, DataflowreplacedysisException {
// return clreplacedContext.getTypeDataflow(method);
// }
// };
//
// driver.execute(argv[0]);
// }
}
18
Source : IsNullValueAnalysis.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* A dataflow replacedysis to detect potential null pointer dereferences.
*
* @author David Hovemeyer
* @see IsNullValue
* @see IsNullValueFrame
* @see IsNullValueFrameModelingVisitor
*/
public clreplaced IsNullValuereplacedysis extends FrameDataflowreplacedysis<IsNullValue, IsNullValueFrame> implements EdgeTypes, IsNullValuereplacedysisFeatures {
static final boolean DEBUG = SystemProperties.getBoolean("inva.debug");
static {
if (DEBUG) {
System.out.println("inva.debug enabled");
}
}
private final MethodGen methodGen;
private final IsNullValueFrameModelingVisitor visitor;
private final ValueNumberDataflow vnaDataflow;
private final CFG cfg;
private final Set<LocationWhereValueBecomesNull> locationWhereValueBecomesNullSet;
private final boolean trackValueNumbers;
private IsNullValueFrame lastFrame;
private IsNullValueFrame instanceOfFrame;
private IsNullValueFrame cachedEntryFact;
private JavaClreplacedAndMethod clreplacedAndMethod;
@CheckForNull
private final PointerEqualityCheck pointerEqualityCheck;
public IsNullValuereplacedysis(MethodDescriptor descriptor, MethodGen methodGen, CFG cfg, ValueNumberDataflow vnaDataflow, TypeDataflow typeDataflow, DepthFirstSearch dfs, replacedertionMethods replacedertionMethods) {
super(dfs);
this.trackValueNumbers = replacedysisContext.currentreplacedysisContext().getBoolProperty(replacedysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_replacedYSIS);
this.methodGen = methodGen;
this.visitor = new IsNullValueFrameModelingVisitor(methodGen.getConstantPool(), replacedertionMethods, vnaDataflow, typeDataflow, trackValueNumbers);
this.vnaDataflow = vnaDataflow;
this.cfg = cfg;
this.locationWhereValueBecomesNullSet = new HashSet<>();
this.pointerEqualityCheck = getForPointerEqualityCheck(cfg, vnaDataflow);
if (DEBUG) {
System.out.println("IsNullValuereplacedysis for " + methodGen.getClreplacedName() + "." + methodGen.getName() + " : " + methodGen.getSignature());
}
}
enum PointerEqualityCheckState {
INIT,
START,
SAW1,
SAW2,
IFEQUAL,
IFNOTEQUAL
}
@CheckForNull
public static PointerEqualityCheck getForPointerEqualityCheck(CFG cfg, ValueNumberDataflow vna) {
PointerEqualityCheckState state = PointerEqualityCheckState.INIT;
int target = Integer.MAX_VALUE;
Location test = null;
for (Location loc : cfg.orderedLocations()) {
Instruction ins = loc.getHandle().getInstruction();
switch(state) {
case INIT:
replacedert ins instanceof org.apache.bcel.generic.NOP;
state = PointerEqualityCheckState.START;
break;
case START:
if (ins instanceof ALOAD) {
state = PointerEqualityCheckState.SAW1;
} else {
return null;
}
break;
case SAW1:
if (ins instanceof ALOAD) {
state = PointerEqualityCheckState.SAW2;
} else {
return null;
}
break;
case SAW2:
if (ins instanceof IF_ACMPNE) {
state = PointerEqualityCheckState.IFEQUAL;
target = ((IF_ACMPNE) ins).getIndex() + loc.getHandle().getPosition();
test = loc;
} else {
return null;
}
break;
case IFEQUAL:
if (ins instanceof org.apache.bcel.generic.ReturnInstruction || ins instanceof ATHROW) {
state = PointerEqualityCheckState.IFNOTEQUAL;
} else if (ins instanceof org.apache.bcel.generic.BranchInstruction) {
return null;
}
break;
case IFNOTEQUAL:
if (loc.getHandle().getPosition() == target) {
try {
ValueNumberFrame vnaFrame = vna.getFactAtLocation(test);
return new PointerEqualityCheck(vnaFrame.getStackValue(0), vnaFrame.getStackValue(1), target);
} catch (DataflowreplacedysisException e) {
return null;
}
} else {
return null;
}
}
}
return null;
}
@CheckForNull
private ValueNumber getKnownNonnullDueToPointerDisequality(ValueNumber knownNull, int pc) {
if (pointerEqualityCheck == null || pc < pointerEqualityCheck.firstValuePC) {
return null;
}
if (pointerEqualityCheck.reg1.equals(knownNull)) {
return pointerEqualityCheck.reg2;
}
if (pointerEqualityCheck.reg2.equals(knownNull)) {
return pointerEqualityCheck.reg1;
}
return null;
}
public static clreplaced PointerEqualityCheck {
final ValueNumber reg1, reg2;
final int firstValuePC;
public PointerEqualityCheck(ValueNumber reg1, ValueNumber reg2, int firstValuePC) {
this.reg1 = reg1;
this.reg2 = reg2;
this.firstValuePC = firstValuePC;
}
}
public void setClreplacedAndMethod(JavaClreplacedAndMethod clreplacedAndMethod) {
this.clreplacedAndMethod = clreplacedAndMethod;
}
public JavaClreplacedAndMethod getClreplacedAndMethod() {
return clreplacedAndMethod;
}
@Override
public IsNullValueFrame createFact() {
return new IsNullValueFrame(methodGen.getMaxLocals(), trackValueNumbers);
}
@Override
public void initEntryFact(IsNullValueFrame result) {
if (cachedEntryFact == null) {
cachedEntryFact = createFact();
cachedEntryFact.setValid();
int numLocals = methodGen.getMaxLocals();
boolean instanceMethod = !methodGen.isStatic();
XMethod xm = XFactory.createXMethod(methodGen.getClreplacedName(), methodGen.getName(), methodGen.getSignature(), methodGen.isStatic());
INullnessAnnotationDatabase db = replacedysisContext.currentreplacedysisContext().getNullnessAnnotationDatabase();
int paramShift = instanceMethod ? 1 : 0;
Type[] argumentTypes = methodGen.getArgumentTypes();
for (int i = 0; i < numLocals; ++i) {
cachedEntryFact.setValue(i, IsNullValue.nonReportingNotNullValue());
}
if (paramShift == 1) {
cachedEntryFact.setValue(0, IsNullValue.nonNullValue());
}
int slot = paramShift;
for (int paramIndex = 0; paramIndex < argumentTypes.length; paramIndex++) {
IsNullValue value;
XMethodParameter methodParameter = new XMethodParameter(xm, paramIndex);
NullnessAnnotation n = db.getResolvedAnnotation(methodParameter, false);
if (n == NullnessAnnotation.CHECK_FOR_NULL) {
// Parameter declared @CheckForNull
value = IsNullValue.parameterMarkedAsMightBeNull(methodParameter);
} else if (n == NullnessAnnotation.NONNULL) {
// Parameter declared @NonNull
// TODO: label this so we don't report defensive programming
// value = false ? IsNullValue.nonNullValue() : IsNullValue.parameterMarkedAsNonnull(methodParameter);
value = IsNullValue.parameterMarkedAsNonnull(methodParameter);
} else {
// Don't know; use default value, normally non-reporting
// nonnull
value = IsNullValue.nonReportingNotNullValue();
}
cachedEntryFact.setValue(slot, value);
slot += argumentTypes[paramIndex].getSize();
}
}
copy(cachedEntryFact, result);
}
@Override
public void transfer(BasicBlock basicBlock, @CheckForNull InstructionHandle end, IsNullValueFrame start, IsNullValueFrame result) throws DataflowreplacedysisException {
startTransfer();
super.transfer(basicBlock, end, start, result);
endTransfer(basicBlock, end, result);
if (end == null) {
ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(Location.getLastLocation(basicBlock));
// purge stale information
if (!vnaFrameAfter.isTop()) {
result.cleanStaleKnowledge(vnaFrameAfter);
}
}
}
public void startTransfer() {
lastFrame = null;
instanceOfFrame = null;
}
public void endTransfer(BasicBlock basicBlock, @CheckForNull InstructionHandle end, IsNullValueFrame result) throws DataflowreplacedysisException {
// Determine if this basic block ends in a redundant branch.
if (end == null) {
if (lastFrame == null) {
result.setDecision(null);
} else {
IsNullConditionDecision decision = getDecision(basicBlock, lastFrame);
result.setDecision(decision);
}
}
lastFrame = null;
instanceOfFrame = null;
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, IsNullValueFrame fact) throws DataflowreplacedysisException {
if (!fact.isValid()) {
return;
}
// If this is the last instruction in the block,
// save the result immediately before the instruction.
if (handle == basicBlock.getLastInstruction()) {
lastFrame = createFact();
lastFrame.copyFrom(fact);
}
if (handle.getInstruction().getOpcode() == Const.INSTANCEOF) {
instanceOfFrame = createFact();
instanceOfFrame.copyFrom(fact);
}
// Model the instruction
visitor.setFrameAndLocation(fact, new Location(handle, basicBlock));
Instruction ins = handle.getInstruction();
visitor.replacedyzeInstruction(ins);
if (!fact.isValid()) {
return;
}
// Special case:
// The instruction may have produced previously seen values
// about which new is-null information is known.
// If any other instances of the produced values exist,
// update their is-null information.
// Also, make a note of any newly-produced null values.
int numProduced = ins.produceStack(methodGen.getConstantPool());
if (numProduced == Const.UNPREDICTABLE) {
throw new DataflowreplacedysisException("Unpredictable stack production", methodGen, handle);
}
int start = fact.getNumSlots() - numProduced;
Location location = new Location(handle, basicBlock);
ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(location);
if (!vnaFrameAfter.isValid()) {
replacedert false : "Invalid VNA after location " + location + " in " + SignatureConverter.convertMethodSignature(methodGen);
return;
}
for (int i = start; i < fact.getNumSlots(); ++i) {
ValueNumber value = vnaFrameAfter.getValue(i);
IsNullValue isNullValue = fact.getValue(i);
for (int j = 0; j < start; ++j) {
ValueNumber otherValue = vnaFrameAfter.getValue(j);
if (value.equals(otherValue)) {
// Same value is in both slots.
// Update the is-null information to match
// the new information.
fact.setValue(j, isNullValue);
}
}
}
if (visitor.getSlotContainingNewNullValue() >= 0) {
ValueNumber newNullValue = vnaFrameAfter.getValue(visitor.getSlotContainingNewNullValue());
addLocationWhereValueBecomesNull(new // ,
LocationWhereValueBecomesNull(// ,
location, // ,
newNullValue));
}
}
private static final BitSet nullComparisonInstructionSet = new BitSet();
static {
nullComparisonInstructionSet.set(Const.IFNULL);
nullComparisonInstructionSet.set(Const.IFNONNULL);
nullComparisonInstructionSet.set(Const.IF_ACMPEQ);
nullComparisonInstructionSet.set(Const.IF_ACMPNE);
}
@Override
public void meetInto(IsNullValueFrame fact, Edge edge, IsNullValueFrame result) throws DataflowreplacedysisException {
meetInto(fact, edge, result, true);
}
public void meetInto(IsNullValueFrame fact, Edge edge, IsNullValueFrame result, boolean propagatePhiNodeInformation) throws DataflowreplacedysisException {
if (fact.isValid()) {
IsNullValueFrame tmpFact = null;
if (!NO_SPLIT_DOWNGRADE_NSP) {
// Downgrade NSP to DNR on non-exception control splits
if (!edge.isExceptionEdge() && cfg.getNumNonExceptionSucessors(edge.getSource()) > 1) {
tmpFact = modifyFrame(fact, null);
tmpFact.downgradeOnControlSplit();
}
}
if (!NO_SWITCH_DEFAULT_AS_EXCEPTION) {
if (edge.getType() == SWITCH_DEFAULT_EDGE) {
tmpFact = modifyFrame(fact, tmpFact);
tmpFact.toExceptionValues();
}
}
final BasicBlock destBlock = edge.getTarget();
if (destBlock.isExceptionHandler()) {
// Exception handler - clear stack and push a non-null value
// to represent the exception.
tmpFact = modifyFrame(fact, tmpFact);
tmpFact.clearStack();
// Downgrade NULL and NSP to DNR if the handler is for
// CloneNotSupportedException or InterruptedException
CodeExceptionGen handler = destBlock.getExceptionGen();
ObjectType catchType = handler.getCatchType();
if (catchType != null) {
String catchClreplaced = catchType.getClreplacedName();
if ("java.lang.CloneNotSupportedException".equals(catchClreplaced) || "java.lang.InterruptedException".equals(catchClreplaced)) {
for (int i = 0; i < tmpFact.getNumSlots(); ++i) {
IsNullValue value = tmpFact.getValue(i);
if (value.isDefinitelyNull() || value.isNullOnSomePath()) {
tmpFact.setValue(i, IsNullValue.nullOnComplexPathValue());
}
}
}
}
// Mark all values as having occurred on an exception path
tmpFact.toExceptionValues();
// Push the exception value
tmpFact.pushValue(IsNullValue.nonNullValue());
} else {
final int edgeType = edge.getType();
final BasicBlock sourceBlock = edge.getSource();
final BasicBlock targetBlock = edge.getTarget();
final ValueNumberFrame targetVnaFrame = vnaDataflow.getStartFact(destBlock);
final ValueNumberFrame sourceVnaFrame = vnaDataflow.getResultFact(sourceBlock);
replacedert targetVnaFrame != null;
// Determine if the edge conveys any information about the
// null/non-null status of operands in the incoming frame.
if (edgeType == IFCMP_EDGE || edgeType == FALL_THROUGH_EDGE) {
IsNullValueFrame resultFact = getResultFact(sourceBlock);
IsNullConditionDecision decision = resultFact.getDecision();
if (decision != null) {
if (!decision.isEdgeFeasible(edgeType)) {
// The incoming edge is infeasible; just use TOP
// as the start fact for this block.
tmpFact = createFact();
tmpFact.setTop();
} else {
ValueNumber valueTested = decision.getValue();
if (valueTested != null) {
// A value has been determined for this edge.
// Use the value to update the is-null
// information in
// the start fact for this block.
if (DEBUG) {
System.out.println("Updating edge information for " + valueTested);
}
final Location atIf = new Location(sourceBlock.getLastInstruction(), sourceBlock);
final ValueNumberFrame prevVnaFrame = vnaDataflow.getFactAtLocation(atIf);
IsNullValue decisionValue = decision.getDecision(edgeType);
if (decisionValue != null) {
if (DEBUG) {
System.out.println("Set decision information");
System.out.println(" " + valueTested + " becomes " + decisionValue);
System.out.println(" at " + targetBlock.getFirstInstruction().getPosition());
System.out.println(" prev available loads: " + prevVnaFrame.availableLoadMapreplacedtring());
System.out.println(" target available loads: " + targetVnaFrame.availableLoadMapreplacedtring());
}
tmpFact = replaceValues(fact, tmpFact, valueTested, prevVnaFrame, targetVnaFrame, decisionValue);
if (decisionValue.isDefinitelyNull()) {
// Make a note of the value that has
// become null
// due to the if comparison.
addLocationWhereValueBecomesNull(new LocationWhereValueBecomesNull(atIf, valueTested));
ValueNumber knownNonnull = getKnownNonnullDueToPointerDisequality(valueTested, atIf.getHandle().getPosition());
if (knownNonnull != null) {
tmpFact = replaceValues(fact, tmpFact, knownNonnull, prevVnaFrame, targetVnaFrame, IsNullValue.checkedNonNullValue());
}
}
}
}
}
}
}
// if (edgeType == IFCMP_EDGE || edgeType ==
// FALL_THROUGH_EDGE)
// If this is a fall-through edge from a null check,
// then we know the value checked is not null.
if (sourceBlock.isNullCheck() && edgeType == FALL_THROUGH_EDGE) {
ValueNumberFrame vnaFrame = vnaDataflow.getStartFact(destBlock);
if (vnaFrame == null) {
throw new IllegalStateException("no vna frame at block entry?");
}
Instruction firstInDest = edge.getTarget().getFirstInstruction().getInstruction();
IsNullValue instance = fact.getInstance(firstInDest, methodGen.getConstantPool());
if (instance.isDefinitelyNull()) {
// If we know the variable is null, this edge is
// infeasible
tmpFact = createFact();
tmpFact.setTop();
} else if (!instance.isDefinitelyNotNull()) {
// If we're not sure that the instance is definitely
// non-null,
// update the is-null information for the dereferenced
// value.
InstructionHandle kaBoomLocation = targetBlock.getFirstInstruction();
ValueNumber replaceMe = vnaFrame.getInstance(firstInDest, methodGen.getConstantPool());
IsNullValue noKaboomNonNullValue = IsNullValue.noKaboomNonNullValue(new Location(kaBoomLocation, targetBlock));
if (DEBUG) {
System.out.println("Start vna fact: " + vnaFrame);
System.out.println("inva fact: " + fact);
System.out.println("\nGenerated NoKaboom value for location " + kaBoomLocation);
System.out.println("Dereferenced " + instance);
System.out.println("On fall through from source block " + sourceBlock);
}
tmpFact = replaceValues(fact, tmpFact, replaceMe, vnaFrame, targetVnaFrame, noKaboomNonNullValue);
}
}
// if (sourceBlock.isNullCheck() && edgeType ==
// FALL_THROUGH_EDGE)
if (propagatePhiNodeInformation && targetVnaFrame.phiNodeForLoads) {
if (DEBUG) {
System.out.println("Is phi node for loads");
}
for (ValueNumber v : fact.getKnownValues()) {
AvailableLoad loadForV = sourceVnaFrame.getLoad(v);
if (DEBUG) {
System.out.println(" " + v + " for " + loadForV);
}
if (loadForV != null) {
ValueNumber[] matchingValueNumbers = targetVnaFrame.getAvailableLoad(loadForV);
if (matchingValueNumbers != null) {
for (ValueNumber v2 : matchingValueNumbers) {
tmpFact = modifyFrame(fact, tmpFact);
tmpFact.useNewValueNumberForLoad(v, v2);
if (DEBUG) {
System.out.println("For " + loadForV + " switch from " + v + " to " + v2);
}
}
}
}
}
}
}
if (tmpFact != null) {
fact = tmpFact;
}
}
// if (fact.isValid())
if (DEBUG) {
System.out.println("At " + edge);
System.out.println("Merge " + fact + " into " + result);
}
// Normal dataflow merge
mergeInto(fact, result);
if (DEBUG) {
System.out.println("getting " + result);
}
}
@Override
protected void mergeInto(IsNullValueFrame other, IsNullValueFrame result) throws DataflowreplacedysisException {
if (other.isTop()) {
return;
}
if (result.isTop()) {
result.copyFrom(other);
return;
}
super.mergeInto(other, result);
// FIXME: update decision?
if (trackValueNumbers) {
result.mergeKnownValuesWith(other);
}
}
@Override
public void starreplacederation() {
// At the beginning of each iteration, clear the set of locations
// where values become null. That way, after the final iteration
// of dataflow replacedysis the set should be as accurate as possible.
locationWhereValueBecomesNullSet.clear();
}
public void addLocationWhereValueBecomesNull(LocationWhereValueBecomesNull locationWhereValueBecomesNull) {
// System.out.println("Location becomes null: " +
// locationWhereValueBecomesNull );
locationWhereValueBecomesNullSet.add(locationWhereValueBecomesNull);
}
public Set<LocationWhereValueBecomesNull> getLocationWhereValueBecomesNullSet() {
return locationWhereValueBecomesNullSet;
}
@Override
protected void mergeValues(IsNullValueFrame otherFrame, IsNullValueFrame resultFrame, int slot) throws DataflowreplacedysisException {
IsNullValue value = IsNullValue.merge(resultFrame.getValue(slot), otherFrame.getValue(slot));
resultFrame.setValue(slot, value);
}
/**
* Determine if the given basic block ends in a redundant null comparison.
*
* @param basicBlock
* the basic block
* @param lastFrame
* the IsNullValueFrame representing values at the final
* instruction of the block
* @return an IsNullConditionDecision object representing the is-null
* information gained about the compared value, or null if no
* information is gained
*/
private IsNullConditionDecision getDecision(BasicBlock basicBlock, IsNullValueFrame lastFrame) throws DataflowreplacedysisException {
replacedert lastFrame != null;
final InstructionHandle lastInSourceHandle = basicBlock.getLastInstruction();
if (lastInSourceHandle == null) {
// doesn't end in null comparison
return null;
}
final short lastInSourceOpcode = lastInSourceHandle.getInstruction().getOpcode();
if (lastInSourceOpcode == Const.IFEQ || lastInSourceOpcode == Const.IFNE) {
// check for instanceof check
InstructionHandle prev = lastInSourceHandle.getPrev();
if (prev == null) {
return null;
}
short secondToLastOpcode = prev.getInstruction().getOpcode();
// System.out.println("Second last opcode: " +
// Const.Const.getOpcodeName(secondToLastOpcode));
if (secondToLastOpcode != Const.INSTANCEOF) {
return null;
}
if (instanceOfFrame == null) {
return null;
}
IsNullValue tos = instanceOfFrame.getTopValue();
boolean isNotInstanceOf = (lastInSourceOpcode != Const.IFNE);
Location atInstanceOf = new Location(prev, basicBlock);
ValueNumberFrame instanceOfVnaFrame = vnaDataflow.getFactAtLocation(atInstanceOf);
// Initially, replacedume neither branch is feasible.
IsNullValue ifcmpDecision = null;
IsNullValue fallThroughDecision = null;
if (tos.isDefinitelyNull()) {
// Predetermined comparison - one branch is infeasible
if (isNotInstanceOf) {
ifcmpDecision = tos;
} else {
// ifnonnull
fallThroughDecision = tos;
}
} else if (tos.isDefinitelyNotNull()) {
return null;
} else {
// As far as we know, both branches feasible
ifcmpDecision = isNotInstanceOf ? tos : IsNullValue.pathSensitiveNonNullValue();
fallThroughDecision = isNotInstanceOf ? IsNullValue.pathSensitiveNonNullValue() : tos;
}
if (DEBUG) {
System.out.println("Checking..." + tos + " -> " + ifcmpDecision + " or " + fallThroughDecision);
}
return new IsNullConditionDecision(instanceOfVnaFrame.getTopValue(), ifcmpDecision, fallThroughDecision);
}
if (!nullComparisonInstructionSet.get(lastInSourceOpcode)) {
// doesn't end in null comparison
return null;
}
Location atIf = new Location(lastInSourceHandle, basicBlock);
ValueNumberFrame prevVnaFrame = vnaDataflow.getFactAtLocation(atIf);
switch(lastInSourceOpcode) {
case Const.IFNULL:
case Const.IFNONNULL:
{
IsNullValue tos = lastFrame.getTopValue();
boolean ifnull = (lastInSourceOpcode == Const.IFNULL);
ValueNumber prevTopValue = prevVnaFrame.getTopValue();
return handleIfNull(tos, prevTopValue, ifnull);
}
case Const.IF_ACMPEQ:
case Const.IF_ACMPNE:
{
IsNullValue tos = lastFrame.getStackValue(0);
IsNullValue nextToTos = lastFrame.getStackValue(1);
boolean tosNull = tos.isDefinitelyNull();
boolean nextToTosNull = nextToTos.isDefinitelyNull();
boolean cmpeq = (lastInSourceOpcode == Const.IF_ACMPEQ);
// Initially, replacedume neither branch is feasible.
IsNullValue ifcmpDecision = null;
IsNullValue fallThroughDecision = null;
ValueNumber value;
if (tosNull && nextToTosNull) {
// Redundant comparison: both values are null, only one branch
// is feasible
// no value will be replaced - just want to
value = null;
// indicate that one of the branches is infeasible
if (cmpeq) {
ifcmpDecision = IsNullValue.pathSensitiveNullValue();
} else {
// cmpne
fallThroughDecision = IsNullValue.pathSensitiveNullValue();
}
} else if (tosNull || nextToTosNull) {
if (tosNull) {
return handleIfNull(nextToTos, prevVnaFrame.getStackValue(1), cmpeq);
}
replacedert nextToTosNull;
return handleIfNull(tos, prevVnaFrame.getStackValue(0), cmpeq);
} else if (tos.isDefinitelyNotNull() && !nextToTos.isDefinitelyNotNull()) {
// learn that nextToTos is definitely non null on one branch
value = prevVnaFrame.getStackValue(1);
if (cmpeq) {
ifcmpDecision = tos;
fallThroughDecision = nextToTos;
} else {
fallThroughDecision = tos;
ifcmpDecision = nextToTos;
}
} else if (!tos.isDefinitelyNotNull() && nextToTos.isDefinitelyNotNull()) {
// learn that tos is definitely non null on one branch
value = prevVnaFrame.getStackValue(0);
if (cmpeq) {
ifcmpDecision = nextToTos;
fallThroughDecision = tos;
} else {
fallThroughDecision = nextToTos;
ifcmpDecision = tos;
}
} else {
// No information gained
return null;
}
return new IsNullConditionDecision(value, ifcmpDecision, fallThroughDecision);
}
default:
throw new IllegalStateException();
}
}
private IsNullConditionDecision handleIfNull(IsNullValue tos, ValueNumber prevTopValue, boolean ifnull) {
// Initially, replacedume neither branch is feasible.
IsNullValue ifcmpDecision = null;
IsNullValue fallThroughDecision = null;
if (tos.isDefinitelyNull()) {
// Predetermined comparison - one branch is infeasible
if (ifnull) {
ifcmpDecision = IsNullValue.pathSensitiveNullValue();
} else {
// ifnonnull
fallThroughDecision = IsNullValue.pathSensitiveNullValue();
}
} else if (tos.isDefinitelyNotNull()) {
// Predetermined comparison - one branch is infeasible
if (ifnull) {
fallThroughDecision = tos.wouldHaveBeenAKaboom() ? tos : IsNullValue.pathSensitiveNonNullValue();
} else {
// ifnonnull
ifcmpDecision = tos.wouldHaveBeenAKaboom() ? tos : IsNullValue.pathSensitiveNonNullValue();
}
} else {
// As far as we know, both branches feasible
ifcmpDecision = ifnull ? IsNullValue.pathSensitiveNullValue() : IsNullValue.pathSensitiveNonNullValue();
fallThroughDecision = ifnull ? IsNullValue.pathSensitiveNonNullValue() : IsNullValue.pathSensitiveNullValue();
}
return new IsNullConditionDecision(prevTopValue, ifcmpDecision, fallThroughDecision);
}
/**
* Update is-null information at a branch target based on information gained
* at a null comparison branch.
*
* @param origFrame
* the original is-null frame at entry to basic block
* @param frame
* the modified version of the is-null entry frame; null if the
* entry frame has not been modified yet
* @param replaceMe
* the ValueNumber in the value number frame at the if comparison
* whose is-null information will be updated
* @param prevVnaFrame
* the ValueNumberFrame at the if comparison
* @param targetVnaFrame
* the ValueNumberFrame at entry to the basic block
* @param replacementValue
* the IsNullValue representing the updated is-null information
* @return a modified IsNullValueFrame with updated is-null information
*/
private IsNullValueFrame replaceValues(IsNullValueFrame origFrame, IsNullValueFrame frame, ValueNumber replaceMe, ValueNumberFrame prevVnaFrame, ValueNumberFrame targetVnaFrame, IsNullValue replacementValue) {
if (!targetVnaFrame.isValid()) {
throw new IllegalArgumentException("Invalid frame in " + methodGen.getClreplacedName() + "." + methodGen.getName() + " : " + methodGen.getSignature());
}
// If required, make a copy of the frame
frame = modifyFrame(origFrame, frame);
replacedert frame.getNumSlots() == targetVnaFrame.getNumSlots() : " frame has " + frame.getNumSlots() + ", target has " + targetVnaFrame.getNumSlots() + " in " + clreplacedAndMethod;
// The VNA frame may have more slots than the IsNullValueFrame
// if it was produced by an IF comparison (whose operand or operands
// are subsequently popped off the stack).
final int targetNumSlots = targetVnaFrame.getNumSlots();
final int prefixNumSlots = Math.min(frame.getNumSlots(), prevVnaFrame.getNumSlots());
if (trackValueNumbers) {
AvailableLoad loadForV = prevVnaFrame.getLoad(replaceMe);
if (DEBUG && loadForV != null) {
System.out.println("For " + replaceMe + " availableLoad is " + loadForV);
ValueNumber[] matchingValueNumbers = targetVnaFrame.getAvailableLoad(loadForV);
if (matchingValueNumbers != null) {
for (ValueNumber v2 : matchingValueNumbers) {
System.out.println(" matches " + v2);
}
}
}
if (loadForV != null) {
ValueNumber[] matchingValueNumbers = targetVnaFrame.getAvailableLoad(loadForV);
if (matchingValueNumbers != null) {
for (ValueNumber v2 : matchingValueNumbers) {
if (!replaceMe.equals(v2)) {
frame.setKnownValue(v2, replacementValue);
if (DEBUG) {
System.out.println("For " + loadForV + " switch from " + replaceMe + " to " + v2);
}
}
}
}
}
frame.setKnownValue(replaceMe, replacementValue);
}
// Here's the deal:
// - "replaceMe" is the value number from the previous frame (at the if
// branch)
// which indicates a value that we have updated is-null information
// about
// - in the target value number frame (at entry to the target block),
// we find the value number in the stack slot corresponding to the
// "replaceMe"
// value; this is the "corresponding" value
// - all instances of the "corresponding" value in the target frame have
// their is-null information updated to "replacementValue"
// This should thoroughly make use of the updated information.
for (int i = 0; i < prefixNumSlots; ++i) {
if (prevVnaFrame.getValue(i).equals(replaceMe)) {
ValueNumber corresponding = targetVnaFrame.getValue(i);
for (int j = 0; j < targetNumSlots; ++j) {
if (targetVnaFrame.getValue(j).equals(corresponding)) {
frame.setValue(j, replacementValue);
}
}
}
}
return frame;
}
public IsNullValueFrame getFactAtMidEdge(Edge edge) throws DataflowreplacedysisException {
BasicBlock block = isForwards() ? edge.getSource() : edge.getTarget();
IsNullValueFrame predFact = createFact();
copy(getResultFact(block), predFact);
edgeTransfer(edge, predFact);
IsNullValueFrame result = createFact();
makeFactTop(result);
meetInto(predFact, edge, result, false);
return result;
}
}
18
Source : ClassContext.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Look up the Method represented by given MethodGen.
*
* @param methodGen
* a MethodGen
* @return the Method represented by the MethodGen
*/
public Method getMethod(MethodGen methodGen) {
Method[] methodList = jclreplaced.getMethods();
for (Method method : methodList) {
if (method.getName().equals(methodGen.getName()) && method.getSignature().equals(methodGen.getSignature()) && method.getAccessFlags() == methodGen.getAccessFlags()) {
return method;
}
}
return null;
}
18
Source : TaintFrame.java
with GNU Lesser General Public License v3.0
from blackarbiter
with GNU Lesser General Public License v3.0
from blackarbiter
public String toString(MethodGen method) {
String[] variables = new String[method.getLocalVariables().length];
LocalVariableGen[] variablesGen = method.getLocalVariables();
for (int i = 0; i < variablesGen.length; i++) {
variables[i] = variablesGen[i].getName();
}
return toString(variables);
}
18
Source : AbstractTaintDetector.java
with GNU Lesser General Public License v3.0
from blackarbiter
with GNU Lesser General Public License v3.0
from blackarbiter
private static String getFullMethodName(MethodGen methodGen) {
String methodNameWithSignature = methodGen.getName() + methodGen.getSignature();
String slashedClreplacedName = methodGen.getClreplacedName().replace('.', '/');
return slashedClreplacedName + "." + methodNameWithSignature;
}
17
Source : NoiseNullDeref.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
private void replacedyzeMethod(ClreplacedContext clreplacedContext, Method method) throws DataflowreplacedysisException, CFGBuilderException {
if (DEBUG || DEBUG_NULLARG) {
System.out.println("Pre FND ");
}
MethodGen methodGen = clreplacedContext.getMethodGen(method);
if (methodGen == null) {
return;
}
// UsagesRequiringNonNullValues uses =
// clreplacedContext.getUsagesRequiringNonNullValues(method);
this.method = method;
if (DEBUG || DEBUG_NULLARG) {
System.out.println("FND: " + SignatureConverter.convertMethodSignature(methodGen));
}
findPreviouslyDeadBlocks();
vnaDataflow = clreplacedContext.getValueNumberDataflow(method);
// Create a NullDerefAndRedundantComparisonFinder object to do the
// actual
// work. It will call back to report null derefs and redundant null
// comparisons
// through the NullDerefAndRedundantComparisonCollector interface we
// implement.
NullDerefAndRedundantComparisonFinder worker = new NullDerefAndRedundantComparisonFinder(clreplacedContext, method, this);
worker.execute();
}
17
Source : FindInconsistentSync2.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Determine whether or not the the given method is a getter method. I.e.,
* if it just returns the value of an instance field.
*
* @param clreplacedContext
* the ClreplacedContext for the clreplaced containing the method
* @param method
* the method
*/
public static boolean isGetterMethod(ClreplacedContext clreplacedContext, Method method) {
MethodGen methodGen = clreplacedContext.getMethodGen(method);
if (methodGen == null) {
return false;
}
InstructionList il = methodGen.getInstructionList();
// System.out.println("Checking getter method: " + method.getName());
if (il.getLength() > 60) {
return false;
}
int count = 0;
for (InstructionHandle ih : il) {
switch(ih.getInstruction().getOpcode()) {
case Const.GETFIELD:
count++;
if (count > 1) {
return false;
}
break;
case Const.PUTFIELD:
case Const.BALOAD:
case Const.CALOAD:
case Const.DALOAD:
case Const.FALOAD:
case Const.IALOAD:
case Const.LALOAD:
case Const.SALOAD:
case Const.AALOAD:
case Const.BASTORE:
case Const.CASTORE:
case Const.DASTORE:
case Const.FASTORE:
case Const.IASTORE:
case Const.LASTORE:
case Const.SASTORE:
case Const.AASTORE:
case Const.PUTSTATIC:
return false;
case Const.INVOKESTATIC:
case Const.INVOKEVIRTUAL:
case Const.INVOKEINTERFACE:
case Const.INVOKESPECIAL:
case Const.GETSTATIC:
}
}
// System.out.println("Found getter method: " + method.getName());
return true;
}
17
Source : DontIgnoreResultOfPutIfAbsent.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
@Override
public void visitClreplacedContext(ClreplacedContext clreplacedContext) {
JavaClreplaced javaClreplaced = clreplacedContext.getJavaClreplaced();
ConstantPool pool = javaClreplaced.getConstantPool();
boolean found = false;
for (Constant constantEntry : pool.getConstantPool()) {
if (constantEntry instanceof ConstantNameAndType) {
ConstantNameAndType nt = (ConstantNameAndType) constantEntry;
if ("putIfAbsent".equals(nt.getName(pool))) {
found = true;
break;
}
}
}
if (!found) {
return;
}
Method[] methodList = javaClreplaced.getMethods();
for (Method method : methodList) {
MethodGen methodGen = clreplacedContext.getMethodGen(method);
if (methodGen == null) {
continue;
}
try {
replacedyzeMethod(clreplacedContext, method);
} catch (DataflowreplacedysisException e) {
bugReporter.logError("Error replacedyzing " + method.toString(), e);
} catch (CFGBuilderException e) {
bugReporter.logError("Error replacedyzing " + method.toString(), e);
}
}
}
17
Source : UnconditionalValueDerefDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public UnconditionalValueDerefDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
throw new MethodUnprofitableException(descriptor);
}
CFG cfg = getCFG(replacedysisCache, descriptor);
ValueNumberDataflow vnd = getValueNumberDataflow(replacedysisCache, descriptor);
UnconditionalValueDerefreplacedysis replacedysis = new UnconditionalValueDerefreplacedysis(getReverseDepthFirstSearch(replacedysisCache, descriptor), getDepthFirstSearch(replacedysisCache, descriptor), cfg, getMethod(replacedysisCache, descriptor), methodGen, vnd, getreplacedertionMethods(replacedysisCache, descriptor.getClreplacedDescriptor()));
IsNullValueDataflow inv = getIsNullValueDataflow(replacedysisCache, descriptor);
// XXX: hack to clear derefs on not-null branches
replacedysis.clearDerefsOnNonNullBranches(inv);
TypeDataflow typeDataflow = getTypeDataflow(replacedysisCache, descriptor);
// XXX: type replacedysis is needed to resolve method calls for
// checking whether call targets unconditionally dereference parameters
replacedysis.setTypeDataflow(typeDataflow);
UnconditionalValueDerefDataflow dataflow = new UnconditionalValueDerefDataflow(cfg, replacedysis);
dataflow.execute();
if (ClreplacedContext.DUMP_DATAFLOW_replacedYSIS) {
dataflow.dumpDataflow(replacedysis);
}
if (UnconditionalValueDerefreplacedysis.DEBUG) {
ClreplacedContext.dumpDataflowInformation(getMethod(replacedysisCache, descriptor), cfg, vnd, inv, dataflow, typeDataflow);
}
return dataflow;
}
17
Source : TypeDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public TypeDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
throw new MethodUnprofitableException(descriptor);
}
CFG cfg = getCFG(replacedysisCache, descriptor);
DepthFirstSearch dfs = getDepthFirstSearch(replacedysisCache, descriptor);
ExceptionSetFactory exceptionSetFactory = getExceptionSetFactory(replacedysisCache, descriptor);
Method method = getMethod(replacedysisCache, descriptor);
Typereplacedysis typereplacedysis = new Typereplacedysis(method, methodGen, cfg, dfs, replacedysisContext.currentreplacedysisContext().getLookupFailureCallback(), exceptionSetFactory);
if (replacedysisContext.currentreplacedysisContext().getBoolProperty(replacedysisFeatures.MODEL_INSTANCEOF)) {
typereplacedysis.setValueNumberDataflow(getValueNumberDataflow(replacedysisCache, descriptor));
}
// Field store type database.
// If present, this can give us more accurate type information
// for values loaded from fields.
typereplacedysis.setFieldStoreTypeDatabase(replacedysisContext.currentreplacedysisContext().getFieldStoreTypeDatabase());
TypeDataflow typeDataflow = new TypeDataflow(cfg, typereplacedysis);
try {
typeDataflow.execute();
} catch (CheckedreplacedysisException e) {
replacedysisContext.logError("Error performing type dataflow replacedysis of " + descriptor, e);
throw e;
}
if (Typereplacedysis.DEBUG || ClreplacedContext.DUMP_DATAFLOW_replacedYSIS) {
ClreplacedContext.dumpTypeDataflow(method, cfg, typeDataflow);
}
return typeDataflow;
}
17
Source : LockDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public LockDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
throw new MethodUnprofitableException(descriptor);
}
ValueNumberDataflow vnaDataflow = getValueNumberDataflow(replacedysisCache, descriptor);
DepthFirstSearch dfs = getDepthFirstSearch(replacedysisCache, descriptor);
CFG cfg = getCFG(replacedysisCache, descriptor);
Lockreplacedysis replacedysis = new Lockreplacedysis(methodGen, vnaDataflow, dfs);
LockDataflow dataflow = new LockDataflow(cfg, replacedysis);
dataflow.execute();
return dataflow;
}
17
Source : CFGDetector.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.Detector2#visitClreplaced(edu.umd.cs.findbugs.clreplacedfile
* .ClreplacedDescriptor)
*/
@Override
public void visitClreplaced(ClreplacedDescriptor clreplacedDescriptor) throws CheckedreplacedysisException {
IreplacedysisCache replacedysisCache = Global.getreplacedysisCache();
JavaClreplaced jclreplaced = replacedysisCache.getClreplacedreplacedysis(JavaClreplaced.clreplaced, clreplacedDescriptor);
clreplacedContext = replacedysisCache.getClreplacedreplacedysis(ClreplacedContext.clreplaced, clreplacedDescriptor);
for (Method m : clreplacedContext.getMethodsInCallOrder()) {
if (m.getCode() == null) {
continue;
}
method = m;
MethodDescriptor methodDescriptor = BCELUtil.getMethodDescriptor(jclreplaced, method);
// Try to get MethodGen. If we can't get one,
// then this method should be skipped.
MethodGen methodGen = replacedysisCache.getMethodreplacedysis(MethodGen.clreplaced, methodDescriptor);
if (methodGen == null) {
continue;
}
CFG cfg = replacedysisCache.getMethodreplacedysis(CFG.clreplaced, methodDescriptor);
visitMethodCFG(methodDescriptor, cfg);
}
}
17
Source : UnconditionalValueDerefAnalysis.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Dataflow replacedysis to find values unconditionally dereferenced in the future.
*
* @author David Hovemeyer
*/
public clreplaced UnconditionalValueDerefreplacedysis extends BackwardDataflowreplacedysis<UnconditionalValueDerefSet> {
public static final boolean DEBUG = SystemProperties.getBoolean("fnd.derefs.debug");
public static final boolean replacedUME_NONZERO_TRIP_LOOPS = SystemProperties.getBoolean("fnd.derefs.nonzerotrip");
public static final boolean IGNORE_DEREF_OF_NCP = SystemProperties.getBoolean("fnd.derefs.ignoreNCP", false);
public static final boolean CHECK_ANNOTATIONS = SystemProperties.getBoolean("fnd.derefs.checkannotations", true);
public static final boolean CHECK_CALLS = SystemProperties.getBoolean("fnd.derefs.checkcalls", true);
public static final boolean DEBUG_CHECK_CALLS = SystemProperties.getBoolean("fnd.derefs.checkcalls.debug");
private static final int[] NULLCHECK1 = { Opcodes.DUP, Opcodes.INVOKESPECIAL, Opcodes.ATHROW };
private static final int[] NULLCHECK2 = { Opcodes.DUP, Opcodes.LDC, Opcodes.INVOKESPECIAL, Opcodes.ATHROW };
private final CFG cfg;
private final Method method;
private final MethodGen methodGen;
private final ValueNumberDataflow vnaDataflow;
private final replacedertionMethods replacedertionMethods;
private IsNullValueDataflow invDataflow;
private TypeDataflow typeDataflow;
/**
* Constructor.
*
* @param rdfs
* the reverse depth-first-search (for the block order)
* @param cfg
* the CFG for the method
* @param methodGen
* the MethodGen for the method
* @param vnaDataflow
* @param replacedertionMethods
* replacedertionMethods for the replacedyzed clreplaced
*/
public UnconditionalValueDerefreplacedysis(ReverseDepthFirstSearch rdfs, DepthFirstSearch dfs, CFG cfg, Method method, MethodGen methodGen, ValueNumberDataflow vnaDataflow, replacedertionMethods replacedertionMethods) {
super(rdfs, dfs);
this.cfg = cfg;
this.methodGen = methodGen;
this.method = method;
this.vnaDataflow = vnaDataflow;
this.replacedertionMethods = replacedertionMethods;
if (DEBUG) {
System.out.println("UnconditionalValueDerefreplacedysis replacedysis " + methodGen.getClreplacedName() + "." + methodGen.getName() + " : " + methodGen.getSignature());
}
}
@Override
public String toString() {
return this.getClreplaced().getSimpleName() + " of " + method;
}
/**
* HACK: use the given is-null dataflow to clear deref sets for values that
* are known to be definitely non-null on a branch.
*
* @param invDataflow
* the IsNullValueDataflow to use
*/
public void clearDerefsOnNonNullBranches(IsNullValueDataflow invDataflow) {
this.invDataflow = invDataflow;
}
public void setTypeDataflow(TypeDataflow typeDataflow) {
this.typeDataflow = typeDataflow;
}
@Override
public boolean isFactValid(UnconditionalValueDerefSet fact) {
return !fact.isTop() && !fact.isBottom();
}
private static boolean check(InstructionHandle h, int[] opcodes) {
for (int opcode : opcodes) {
if (h == null) {
return false;
}
short opcode2 = h.getInstruction().getOpcode();
if (opcode == Const.LDC) {
switch(opcode2) {
case Const.LDC:
case Const.ALOAD:
case Const.ALOAD_0:
case Const.ALOAD_1:
case Const.ALOAD_2:
case Const.ALOAD_3:
break;
default:
return false;
}
} else if (opcode2 != opcode) {
return false;
}
h = h.getNext();
}
return true;
}
public static boolean isNullCheck(InstructionHandle h, ConstantPoolGen cpg) {
if (!(h.getInstruction() instanceof IFNONNULL)) {
return false;
}
h = h.getNext();
final Instruction newInstruction = h.getInstruction();
if (!(newInstruction instanceof NEW)) {
return false;
}
final ObjectType loadClreplacedType = ((NEW) newInstruction).getLoadClreplacedType(cpg);
if (!"java.lang.NullPointerException".equals(loadClreplacedType.getClreplacedName())) {
return false;
}
h = h.getNext();
return check(h, NULLCHECK1) || check(h, NULLCHECK2);
}
private void handleNullCheck(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowreplacedysisException {
if (reportPotentialDereference(location, invDataflow.getFactAtLocation(location))) {
ValueNumber vn = vnaFrame.getTopValue();
fact.addDeref(vn, location);
}
}
public static boolean reportPotentialDereference(Location location, IsNullValueFrame invFrame) throws DataflowreplacedysisException {
if (!invFrame.isValid()) {
return false;
}
IsNullValue value = invFrame.getTopValue();
return !(value.isDefinitelyNotNull() || value.isDefinitelyNull());
}
@Override
public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, UnconditionalValueDerefSet fact) throws DataflowreplacedysisException {
Instruction instruction = handle.getInstruction();
if (fact.isTop()) {
return;
}
Location location = new Location(handle, basicBlock);
// If this is a call to an replacedertion method,
// change the dataflow value to be TOP.
// We don't want to report future derefs that would
// be guaranteed only if the replacedertion methods
// returns normally.
// TODO: at some point, evaluate whether we should revisit this
if (// || handle.getInstruction() instanceof ATHROW
isreplacedertion(handle)) {
if (DEBUG) {
System.out.println("MAKING BOTTOM0 AT: " + location);
}
fact.clear();
return;
}
// Get value number frame
ValueNumberFrame vnaFrame = vnaDataflow.getFactAtLocation(location);
if (!vnaFrame.isValid()) {
if (DEBUG) {
System.out.println("MAKING TOP1 AT: " + location);
}
// Probably dead code.
// replacedume this location can't be reached.
makeFactTop(fact);
return;
}
if (isNullCheck(handle, methodGen.getConstantPool())) {
handleNullCheck(location, vnaFrame, fact);
}
// Check for calls to a method that unconditionally dereferences
// a parameter. Mark any such arguments as derefs.
if (CHECK_CALLS && instruction instanceof InvokeInstruction) {
checkUnconditionalDerefDatabase(location, vnaFrame, fact);
}
// If this is a method call instruction,
// check to see if any of the parameters are @NonNull,
// and treat them as dereferences.
if (CHECK_ANNOTATIONS && instruction instanceof InvokeInstruction) {
checkNonNullParams(location, vnaFrame, fact);
}
if (CHECK_ANNOTATIONS && instruction instanceof ARETURN) {
XMethod thisMethod = XFactory.createXMethod(methodGen);
checkNonNullReturnValue(thisMethod, location, vnaFrame, fact);
}
if (CHECK_ANNOTATIONS && (instruction instanceof PUTFIELD || instruction instanceof PUTSTATIC)) {
checkNonNullPutField(location, vnaFrame, fact);
}
// Check to see if an instance value is dereferenced here
checkInstance(location, vnaFrame, fact);
/*
if (false) {
fact.cleanDerefSet(location, vnaFrame);
}*/
if (DEBUG && fact.isTop()) {
System.out.println("MAKING TOP2 At: " + location);
}
}
/**
* Check method call at given location to see if it unconditionally
* dereferences a parameter. Mark any such arguments as derefs.
*
* @param location
* the Location of the method call
* @param vnaFrame
* ValueNumberFrame at the Location
* @param fact
* the dataflow value to modify
* @throws DataflowreplacedysisException
*/
private void checkUnconditionalDerefDatabase(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowreplacedysisException {
ConstantPoolGen constantPool = methodGen.getConstantPool();
for (ValueNumber vn : checkUnconditionalDerefDatabase(location, vnaFrame, constantPool, invDataflow.getFactAtLocation(location), typeDataflow)) {
fact.addDeref(vn, location);
}
}
public static Set<ValueNumber> checkUnconditionalDerefDatabase(Location location, ValueNumberFrame vnaFrame, ConstantPoolGen constantPool, @CheckForNull IsNullValueFrame invFrame, TypeDataflow typeDataflow) throws DataflowreplacedysisException {
if (invFrame != null && !invFrame.isValid()) {
return Collections.emptySet();
}
InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction();
SignatureParser sigParser = new SignatureParser(inv.getSignature(constantPool));
int numParams = sigParser.getNumParameters();
if (numParams == 0 || !sigParser.hasReferenceParameters()) {
return Collections.emptySet();
}
ParameterNullnessPropertyDatabase database = replacedysisContext.currentreplacedysisContext().getUnconditionalDerefParamDatabase();
if (database == null) {
if (DEBUG_CHECK_CALLS) {
System.out.println("no database!");
}
return Collections.emptySet();
}
TypeFrame typeFrame = typeDataflow.getFactAtLocation(location);
if (!typeFrame.isValid()) {
if (DEBUG_CHECK_CALLS) {
System.out.println("invalid type frame!");
}
return Collections.emptySet();
}
try {
Set<XMethod> targetSet = Hierarchy2.resolveMethodCallTargets(inv, typeFrame, constantPool);
if (targetSet.isEmpty()) {
return Collections.emptySet();
}
if (DEBUG_CHECK_CALLS) {
System.out.println("target set size: " + targetSet.size());
}
// Compute the intersection of all properties
ParameterProperty derefParamSet = null;
for (XMethod target : targetSet) {
if (target.isStub()) {
continue;
}
if (DEBUG_CHECK_CALLS) {
System.out.print("Checking: " + target + ": ");
}
ParameterProperty targetDerefParamSet = database.getProperty(target.getMethodDescriptor());
if (targetDerefParamSet == null) {
// Hmm...no information for this target.
// replacedume it doesn't dereference anything
if (DEBUG_CHECK_CALLS) {
System.out.println("==> no information, replacedume no guaranteed dereferences");
}
return Collections.emptySet();
}
if (DEBUG_CHECK_CALLS) {
System.out.println("==> " + targetDerefParamSet);
}
if (derefParamSet == null) {
derefParamSet = new ParameterProperty();
derefParamSet.copyFrom(targetDerefParamSet);
} else {
derefParamSet.intersectWith(targetDerefParamSet);
}
}
if (derefParamSet == null || derefParamSet.isEmpty()) {
if (DEBUG) {
System.out.println("** Nothing");
}
return Collections.emptySet();
}
if (DEBUG_CHECK_CALLS) {
System.out.println("** Summary of call @ " + location.getHandle().getPosition() + ": " + derefParamSet);
}
HashSet<ValueNumber> requiredToBeNonnull = new HashSet<>();
for (int i = 0; i < numParams; i++) {
if (!derefParamSet.hasProperty(i)) {
continue;
}
int argSlot = vnaFrame.getStackLocation(sigParser.getSlotsFromTopOfStackForParameter(i));
if (invFrame != null && !reportDereference(invFrame, argSlot)) {
continue;
}
if (DEBUG_CHECK_CALLS) {
System.out.println(" dereference @ " + location.getHandle().getPosition() + " of parameter " + i);
}
requiredToBeNonnull.add(vnaFrame.getValue(argSlot));
}
return requiredToBeNonnull;
} catch (ClreplacedNotFoundException e) {
replacedysisContext.reportMissingClreplaced(e);
}
return Collections.emptySet();
}
public static final boolean VERBOSE_NULLARG_DEBUG = SystemProperties.getBoolean("fnd.debug.nullarg.verbose");
/**
* If this is a method call instruction, check to see if any of the
* parameters are @NonNull, and treat them as dereferences.
*
* @param location
* the Location of the instruction
* @param vnaFrame
* the ValueNumberFrame at the Location of the instruction
* @param fact
* the dataflow value to modify
*
* @throws DataflowreplacedysisException
*/
private void checkNonNullReturnValue(XMethod thisMethod, Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowreplacedysisException {
INullnessAnnotationDatabase database = replacedysisContext.currentreplacedysisContext().getNullnessAnnotationDatabase();
if (database.getResolvedAnnotation(thisMethod, true) != NullnessAnnotation.NONNULL) {
return;
}
if (reportPotentialDereference(location, invDataflow.getFactAtLocation(location))) {
ValueNumber vn = vnaFrame.getTopValue();
fact.addDeref(vn, location);
}
}
/**
* If this is a putfield or putstatic instruction, check to see if the field
* is @NonNull, and treat it as dereferences.
*
* @param location
* the Location of the instruction
* @param vnaFrame
* the ValueNumberFrame at the Location of the instruction
* @param fact
* the dataflow value to modify
* @throws DataflowreplacedysisException
*/
private void checkNonNullPutField(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowreplacedysisException {
INullnessAnnotationDatabase database = replacedysisContext.currentreplacedysisContext().getNullnessAnnotationDatabase();
FieldInstruction fieldIns = (FieldInstruction) location.getHandle().getInstruction();
XField field = XFactory.createXField(fieldIns, methodGen.getConstantPool());
char firstChar = field.getSignature().charAt(0);
if (firstChar != 'L' && firstChar != '[') {
return;
}
NullnessAnnotation resolvedAnnotation = database.getResolvedAnnotation(field, true);
if (resolvedAnnotation == NullnessAnnotation.NONNULL) {
IsNullValueFrame invFrame = invDataflow.getFactAtLocation(location);
if (!invFrame.isValid()) {
return;
}
IsNullValue value = invFrame.getTopValue();
if (reportDereference(value)) {
ValueNumber vn = vnaFrame.getTopValue();
fact.addDeref(vn, location);
}
}
}
/**
* If this is a method call instruction, check to see if any of the
* parameters are @NonNull, and treat them as dereferences.
*
* @param location
* the Location of the instruction
* @param vnaFrame
* the ValueNumberFrame at the Location of the instruction
* @param fact
* the dataflow value to modify
* @throws DataflowreplacedysisException
*/
private void checkNonNullParams(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowreplacedysisException {
ConstantPoolGen constantPool = methodGen.getConstantPool();
Set<ValueNumber> nonNullParams = checkNonNullParams(location, vnaFrame, constantPool, method, invDataflow.getFactAtLocation(location));
for (ValueNumber vn : nonNullParams) {
fact.addDeref(vn, location);
}
}
public static Set<ValueNumber> checkAllNonNullParams(Location location, ValueNumberFrame vnaFrame, ConstantPoolGen constantPool, @CheckForNull Method method, @CheckForNull IsNullValueDataflow invDataflow, TypeDataflow typeDataflow) throws DataflowreplacedysisException {
IsNullValueFrame invFrame = null;
if (invDataflow != null) {
invFrame = invDataflow.getFactAtLocation(location);
}
Set<ValueNumber> result1 = checkNonNullParams(location, vnaFrame, constantPool, method, invFrame);
Set<ValueNumber> result2 = checkUnconditionalDerefDatabase(location, vnaFrame, constantPool, invFrame, typeDataflow);
if (result1.isEmpty()) {
return result2;
}
if (result2.isEmpty()) {
return result1;
}
result1.addAll(result2);
return result1;
}
public static Set<ValueNumber> checkNonNullParams(Location location, ValueNumberFrame vnaFrame, ConstantPoolGen constantPool, @CheckForNull Method method, @CheckForNull IsNullValueFrame invFrame) throws DataflowreplacedysisException {
if (invFrame != null && !invFrame.isValid()) {
return Collections.emptySet();
}
INullnessAnnotationDatabase database = replacedysisContext.currentreplacedysisContext().getNullnessAnnotationDatabase();
InvokeInstruction inv = (InvokeInstruction) location.getHandle().getInstruction();
if (inv instanceof INVOKEDYNAMIC) {
// ignore indy, it's only used to create lambda instances
return Collections.emptySet();
}
XMethod called = XFactory.createXMethod(inv, constantPool);
SignatureParser sigParser = new SignatureParser(called.getSignature());
int numParams = sigParser.getNumParameters();
Set<ValueNumber> result = new HashSet<>();
Iterator<String> parameterIterator = sigParser.parameterSignatureIterator();
for (int i = 0; i < numParams; i++) {
String parameterSignature = parameterIterator.next();
char firstChar = parameterSignature.charAt(0);
if (firstChar != 'L' && firstChar != '[') {
continue;
}
int offset = sigParser.getSlotsFromTopOfStackForParameter(i);
if (invFrame != null) {
int slot = invFrame.getStackLocation(offset);
if (!reportDereference(invFrame, slot)) {
continue;
}
}
if (database.parameterMustBeNonNull(called, i)) {
int catchSizeNPE = Util.getSizeOfSurroundingTryBlock(method, "java/lang/NullPointerException", location.getHandle().getPosition());
int catchSizeNFE = Util.getSizeOfSurroundingTryBlock(method, "java/lang/NumberFormatException", location.getHandle().getPosition());
if (catchSizeNPE == Integer.MAX_VALUE && (!Values.DOTTED_JAVA_LANG_INTEGER.equals(called.getClreplacedName()) || catchSizeNFE == Integer.MAX_VALUE)) {
// Get the corresponding value number
ValueNumber vn = vnaFrame.getArgument(inv, constantPool, i, sigParser);
result.add(vn);
}
}
}
return result;
}
/**
* Check to see if the instruction has a null check replacedociated with it, and
* if so, add a dereference.
*
* @param location
* the Location of the instruction
* @param vnaFrame
* ValueNumberFrame at the Location of the instruction
* @param fact
* the dataflow value to modify
* @throws DataflowreplacedysisException
*/
private void checkInstance(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowreplacedysisException {
// See if this instruction has a null check.
// If it does, the fall through predecessor will be
// identify itself as the null check.
if (!location.isFirstInstructionInBasicBlock()) {
return;
}
if (invDataflow == null) {
return;
}
BasicBlock fallThroughPredecessor = cfg.getPredecessorWithEdgeType(location.getBasicBlock(), EdgeTypes.FALL_THROUGH_EDGE);
if (fallThroughPredecessor == null || !fallThroughPredecessor.isNullCheck()) {
return;
}
// Get the null-checked value
ValueNumber vn = vnaFrame.getInstance(location.getHandle().getInstruction(), methodGen.getConstantPool());
// Ignore dereferences of this
if (!methodGen.isStatic()) {
ValueNumber v = vnaFrame.getValue(0);
if (v.equals(vn)) {
return;
}
}
if (vn.hasFlag(ValueNumber.CONSTANT_CLreplaced_OBJECT)) {
return;
}
IsNullValueFrame startFact = null;
startFact = invDataflow.getStartFact(fallThroughPredecessor);
if (!startFact.isValid()) {
return;
}
int slot = startFact.getInstanceSlot(location.getHandle().getInstruction(), methodGen.getConstantPool());
if (!reportDereference(startFact, slot)) {
return;
}
if (DEBUG) {
System.out.println("FOUND GUARANTEED DEREFERENCE");
System.out.println("Load: " + vnaFrame.getLoad(vn));
System.out.println("Pred: " + fallThroughPredecessor);
System.out.println("startFact: " + startFact);
System.out.println("Location: " + location);
System.out.println("Value number frame: " + vnaFrame);
System.out.println("Dereferenced valueNumber: " + vn);
System.out.println("invDataflow: " + startFact);
System.out.println("IGNORE_DEREF_OF_NCP: " + IGNORE_DEREF_OF_NCP);
}
// Mark the value number as being dereferenced at this location
fact.addDeref(vn, location);
}
private static boolean reportDereference(IsNullValueFrame invFrameAtNullCheck, int instance) {
return reportDereference(invFrameAtNullCheck.getValue(instance));
}
private static boolean reportDereference(IsNullValue value) {
return !(value.isDefinitelyNotNull() || value.isDefinitelyNull() || (IGNORE_DEREF_OF_NCP && value.isNullOnComplicatedPath()));
}
/**
* Return whether or not given instruction is an replacedertion.
*
* @param handle
* the instruction
* @return true if instruction is an replacedertion, false otherwise
*/
private boolean isreplacedertion(InstructionHandle handle) {
return replacedertionMethods.isreplacedertionHandle(handle, methodGen.getConstantPool());
}
@Override
public void copy(UnconditionalValueDerefSet source, UnconditionalValueDerefSet dest) {
dest.makeSameAs(source);
}
@Override
public UnconditionalValueDerefSet createFact() {
return new UnconditionalValueDerefSet(vnaDataflow.getreplacedysis().getNumValuesAllocated());
}
@Override
public void initEntryFact(UnconditionalValueDerefSet result) throws DataflowreplacedysisException {
result.clear();
}
// /* (non-Javadoc)
// * @see
// edu.umd.cs.findbugs.ba.Dataflowreplacedysis#initResultFact(java.lang.Object)
// */
// public void initResultFact(UnconditionalValueDerefSet result) {
// result.setIsTop();
// }
@Override
public void makeFactTop(UnconditionalValueDerefSet fact) {
fact.setIsTop();
}
@Override
public boolean isTop(UnconditionalValueDerefSet fact) {
return fact.isTop();
}
@Override
public void meetInto(UnconditionalValueDerefSet fact, Edge edge, UnconditionalValueDerefSet result) throws DataflowreplacedysisException {
meetInto(fact, edge, result, false);
}
public void meetInto(UnconditionalValueDerefSet fact, Edge edge, UnconditionalValueDerefSet result, boolean onlyEdge) {
if (isExceptionEdge(edge) && !onlyEdge) {
if (DEBUG) {
System.out.println("Skipping exception edge");
}
return;
}
ValueNumber knownNonnullOnBranch = null;
// Edge transfer function
if (isFactValid(fact)) {
fact = propagateDerefSetsToMergeInputValues(fact, edge);
if (invDataflow != null) {
knownNonnullOnBranch = findValueKnownNonnullOnBranch(fact, edge);
if (knownNonnullOnBranch != null) {
fact = duplicateFact(fact);
fact.clearDerefSet(knownNonnullOnBranch);
}
}
}
boolean isBackEdge = edge.isBackwardInBytecode();
Set<Integer> loopExitBranches = ClreplacedContext.getLoopExitBranches(method, methodGen);
replacedert loopExitBranches != null;
boolean sourceIsTopOfLoop = edge.sourceIsTopOfLoop(loopExitBranches);
if (sourceIsTopOfLoop && edge.getType() == EdgeTypes.FALL_THROUGH_EDGE) {
isBackEdge = true;
}
/*
if (false && (edge.getType() == EdgeTypes.IFCMP_EDGE || sourceIsTopOfLoop)) {
System.out.println("Meet into " + edge);
System.out.println(" foo2: " + sourceIsTopOfLoop);
System.out.println(" getType: " + edge.getType());
System.out.println(" Backedge according to bytecode: " + isBackEdge);
System.out.println(" Fact hashCode: " + System.idenreplacedyHashCode(result));
System.out.println(" Initial fact: " + result);
System.out.println(" Edge fact: " + fact);
}
*/
if (result.isTop() || fact.isBottom()) {
// Make result identical to other fact
copy(fact, result);
if (replacedUME_NONZERO_TRIP_LOOPS && isBackEdge && !fact.isTop()) {
result.resultsFromBackEdge = true;
}
} else if (replacedUME_NONZERO_TRIP_LOOPS && isBackEdge && !fact.isTop()) {
result.unionWith(fact, vnaDataflow.getreplacedysis().getFactory());
result.resultsFromBackEdge = true;
if (DEBUG) {
System.out.println("\n Forcing union of " + System.idenreplacedyHashCode(result) + " due to backedge info");
System.out.println(" result: " + result);
}
} else if (result.isBottom() || fact.isTop()) {
// No change in result fact
} else {
// Dataflow merge
// (intersection of unconditional deref values)
if (replacedUME_NONZERO_TRIP_LOOPS && result.resultsFromBackEdge) {
result.backEdgeUpdateCount++;
if (result.backEdgeUpdateCount < 10) {
if (DEBUG) {
System.out.println("\n Union update of " + System.idenreplacedyHashCode(result) + " due to backedge info");
}
result.unionWith(fact, vnaDataflow.getreplacedysis().getFactory());
return;
}
}
result.mergeWith(fact, knownNonnullOnBranch, vnaDataflow.getreplacedysis().getFactory());
if (DEBUG) {
System.out.println(" updated: " + System.idenreplacedyHashCode(result));
System.out.println(" result: " + result);
}
}
if (DEBUG && isBackEdge && edge.getType() == EdgeTypes.IFCMP_EDGE) {
System.out.println(" result: " + result);
}
}
/**
* Find out if any VNs in the source block contribute to unconditionally
* dereferenced VNs in the target block. If so, the VN in the source block
* is also unconditionally dereferenced, and we must propagate the target
* VN's dereferences.
*
* @param fact
* a dataflow value
* @param edge
* edge to check for merge input values
* @return possibly-modified dataflow value
*/
private UnconditionalValueDerefSet propagateDerefSetsToMergeInputValues(UnconditionalValueDerefSet fact, Edge edge) {
ValueNumberFrame blockValueNumberFrame = vnaDataflow.getResultFact(edge.getSource());
ValueNumberFrame targetValueNumberFrame = vnaDataflow.getStartFact(edge.getTarget());
UnconditionalValueDerefSet originalFact = fact;
fact = duplicateFact(fact);
if (blockValueNumberFrame.isValid() && targetValueNumberFrame.isValid()) {
int slots = 0;
if (targetValueNumberFrame.getNumSlots() == blockValueNumberFrame.getNumSlots()) {
slots = targetValueNumberFrame.getNumSlots();
} else if (targetValueNumberFrame.getNumLocals() == blockValueNumberFrame.getNumLocals()) {
slots = targetValueNumberFrame.getNumLocals();
}
if (slots > 0) {
if (DEBUG) {
System.out.println("** Valid VNA frames for " + edge);
System.out.println("** Block : " + blockValueNumberFrame);
System.out.println("** Target: " + targetValueNumberFrame);
}
for (int i = 0; i < slots; i++) {
ValueNumber blockVN = blockValueNumberFrame.getValue(i);
ValueNumber targetVN = targetValueNumberFrame.getValue(i);
if (blockVN.equals(targetVN)) {
continue;
}
fact.clearDerefSet(blockVN);
if (originalFact.isUnconditionallyDereferenced(targetVN)) {
fact.setDerefSet(blockVN, originalFact.getUnconditionalDerefLocationSet(targetVN));
}
}
// for all slots
for (ValueNumber blockVN : blockValueNumberFrame.valueNumbersForLoads()) {
AvailableLoad load = blockValueNumberFrame.getLoad(blockVN);
if (load == null) {
continue;
}
ValueNumber[] targetVNs = targetValueNumberFrame.getAvailableLoad(load);
if (targetVNs != null) {
for (ValueNumber targetVN : targetVNs) {
if (targetVN.hasFlag(ValueNumber.PHI_NODE) && fact.isUnconditionallyDereferenced(targetVN) && !fact.isUnconditionallyDereferenced(blockVN)) {
// Block VN is also dereferenced
// unconditionally.
AvailableLoad targetLoad = targetValueNumberFrame.getLoad(targetVN);
if (!load.equals(targetLoad)) {
continue;
}
if (DEBUG) {
System.out.println("** Copy vn derefs for " + load + " from " + targetVN + " --> " + blockVN);
System.out.println("** block phi for " + System.idenreplacedyHashCode(blockValueNumberFrame) + " is " + blockValueNumberFrame.phiNodeForLoads);
System.out.println("** target phi for " + System.idenreplacedyHashCode(targetValueNumberFrame) + " is " + targetValueNumberFrame.phiNodeForLoads);
}
fact.setDerefSet(blockVN, fact.getUnconditionalDerefLocationSet(targetVN));
}
}
}
}
}
}
if (DEBUG) {
System.out.println("Target VNF: " + targetValueNumberFrame);
System.out.println("Block VNF: " + blockValueNumberFrame);
System.out.println("fact: " + fact);
}
fact.cleanDerefSet(null, blockValueNumberFrame);
return fact;
}
/**
* Return a duplicate of given dataflow fact.
*
* @param fact
* a dataflow fact
* @return a duplicate of the input dataflow fact
*/
private UnconditionalValueDerefSet duplicateFact(UnconditionalValueDerefSet fact) {
UnconditionalValueDerefSet copyOfFact = createFact();
copy(fact, copyOfFact);
fact = copyOfFact;
return fact;
}
/**
* Clear deref sets of values if this edge is the non-null branch of an if
* comparison.
*
* @param fact
* a datflow fact
* @param edge
* edge to check
* @return possibly-modified dataflow fact
*/
@CheckForNull
private ValueNumber findValueKnownNonnullOnBranch(UnconditionalValueDerefSet fact, Edge edge) {
IsNullValueFrame invFrame = invDataflow.getResultFact(edge.getSource());
if (!invFrame.isValid()) {
return null;
}
IsNullConditionDecision decision = invFrame.getDecision();
if (decision == null) {
return null;
}
IsNullValue inv = decision.getDecision(edge.getType());
if (inv == null || !inv.isDefinitelyNotNull()) {
return null;
}
ValueNumber value = decision.getValue();
if (DEBUG) {
System.out.println("Value number " + value + " is known nonnull on " + edge);
}
return value;
}
/**
* Determine whether dataflow should be propagated on given edge.
*
* @param edge
* the edge
* @return true if dataflow should be propagated on the edge, false
* otherwise
*/
private boolean isExceptionEdge(Edge edge) {
boolean isExceptionEdge = edge.isExceptionEdge();
if (isExceptionEdge) {
if (DEBUG) {
System.out.println("NOT Ignoring " + edge);
}
// false
return true;
}
if (edge.getType() != EdgeTypes.FALL_THROUGH_EDGE) {
return false;
}
InstructionHandle h = edge.getSource().getLastInstruction();
return h != null && h.getInstruction() instanceof IFNONNULL && isNullCheck(h, methodGen.getConstantPool());
}
@Override
public boolean same(UnconditionalValueDerefSet fact1, UnconditionalValueDerefSet fact2) {
return fact1.resultsFromBackEdge || fact1.isSameAs(fact2);
}
@Override
public void starreplacederation() {
// System.out.println("replacedysis iteration in " +
// methodGen.getClreplacedName() + " on " + methodGen.toString());
}
@Override
public int getLastUpdateTimestamp(UnconditionalValueDerefSet fact) {
return fact.getLastUpdateTimestamp();
}
@Override
public void setLastUpdateTimestamp(UnconditionalValueDerefSet fact, int lastUpdate) {
fact.setLastUpdateTimestamp(lastUpdate);
}
// public static void main(String[] args) throws Exception {
// if (args.length != 1) {
// System.err.println("Usage: " +
// UnconditionalValueDerefreplacedysis.clreplaced.getName() + " <clreplacedfile>");
// System.exit(1);
// }
//
// DataflowTestDriver<UnconditionalValueDerefSet,
// UnconditionalValueDerefreplacedysis> driver =
// new DataflowTestDriver<UnconditionalValueDerefSet,
// UnconditionalValueDerefreplacedysis>() {
// /* (non-Javadoc)
// * @see
// edu.umd.cs.findbugs.ba.DataflowTestDriver#createDataflow(edu.umd.cs.findbugs.ba.ClreplacedContext,
// org.apache.bcel.clreplacedfile.Method)
// */
// @Override
// public Dataflow<UnconditionalValueDerefSet,
// UnconditionalValueDerefreplacedysis> createDataflow(ClreplacedContext
// clreplacedContext, Method method) throws CFGBuilderException,
// DataflowreplacedysisException {
// return clreplacedContext.getUnconditionalValueDerefDataflow(method);
// }
// };
// if (SystemProperties.getBoolean("forwardcfg")) {
// driver.overrideIsForwards();
// }
// driver.execute(args[0]);
// }
}
17
Source : TaintDataflowEngine.java
with GNU Lesser General Public License v3.0
from blackarbiter
with GNU Lesser General Public License v3.0
from blackarbiter
@Override
public TaintDataflow replacedyze(IreplacedysisCache cache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
if (FindSecBugsGlobalConfig.getInstance().isDebugPrintInstructionVisited() || FindSecBugsGlobalConfig.getInstance().isDebugPrintInvocationVisited()) {
System.out.println("==[ Method: " + descriptor.getName() + " ]==");
}
CFG cfg = cache.getMethodreplacedysis(CFG.clreplaced, descriptor);
DepthFirstSearch dfs = cache.getMethodreplacedysis(DepthFirstSearch.clreplaced, descriptor);
MethodGen methodGen = cache.getMethodreplacedysis(MethodGen.clreplaced, descriptor);
Taintreplacedysis replacedysis = new Taintreplacedysis(methodGen, dfs, descriptor, taintConfig);
TaintDataflow flow = new TaintDataflow(cfg, replacedysis);
flow.execute();
replacedysis.finishreplacedysis();
if (CONFIG.isDebugOutputTaintConfigs() && writer != null) {
TaintMethodConfig derivedConfig = taintConfig.get(getSlashedMethodName(methodGen));
if (derivedConfig != null) {
try {
writer.append(getSlashedMethodName(methodGen) + ":" + derivedConfig + "\n");
writer.flush();
} catch (IOException ex) {
replacedysisContext.logError("Cannot write derived configs", ex);
}
}
}
return flow;
}
17
Source : ObjectDeserializationDetector.java
with GNU Lesser General Public License v3.0
from blackarbiter
with GNU Lesser General Public License v3.0
from blackarbiter
private void replacedyzeMethod(Method m, ClreplacedContext clreplacedContext) throws CFGBuilderException, DataflowreplacedysisException {
MethodGen methodGen = clreplacedContext.getMethodGen(m);
ConstantPoolGen cpg = clreplacedContext.getConstantPoolGen();
CFG cfg = clreplacedContext.getCFG(m);
if (methodGen == null || methodGen.getInstructionList() == null) {
// No instruction .. nothing to do
return;
}
for (Iterator<Location> i = cfg.locationIterator(); i.hasNext(); ) {
Location location = i.next();
Instruction inst = location.getHandle().getInstruction();
//
if (inst instanceof InvokeInstruction) {
// System.out.println(inst.getName());
InvokeInstruction invoke = (InvokeInstruction) inst;
String clreplacedName = invoke.getClreplacedName(cpg);
if ("java.io.ObjectInputStream".equals(clreplacedName) || clreplacedName.contains("InputStream") || InterfaceUtils.isSubtype(clreplacedName, "java.io.ObjectInputStream")) {
String methodName = invoke.getMethodName(cpg);
if (OBJECT_INPUTSTREAM_READ_METHODS.contains(methodName)) {
JavaClreplaced clz = clreplacedContext.getJavaClreplaced();
bugReporter.reportBug(//
new BugInstance(this, OBJECT_DESERIALIZATION_TYPE, HIGH_PRIORITY).addClreplaced(clz).addMethod(clz, m).addSourceLine(clreplacedContext, m, location));
}
}
}
}
}
17
Source : GoogleApiKeyDetector.java
with GNU Lesser General Public License v3.0
from blackarbiter
with GNU Lesser General Public License v3.0
from blackarbiter
@Override
public void visitClreplacedContext(ClreplacedContext clreplacedContext) {
JavaClreplaced javaClreplaced = clreplacedContext.getJavaClreplaced();
boolean keyStringField = false;
for (Field f : javaClreplaced.getFields()) {
if (f.getName().equals("keyString")) {
// The expected field name
keyStringField = true;
break;
}
}
if (!keyStringField) {
// No key field identify
return;
}
// Clreplaced name left unchanged
if (javaClreplaced.getClreplacedName().contains("UrlSigner")) {
bugReporter.reportBug(//
new BugInstance(this, HARD_CODE_PreplacedWORD_TYPE, Priorities.NORMAL_PRIORITY).addClreplaced(javaClreplaced).addField(new FieldVariable(javaClreplaced.getClreplacedName(), "keyString", "Ljava/lang/String;")));
return;
}
// Event if the clreplaced name was refactor, the method "signRequest" would probably be left.
for (Method m : javaClreplaced.getMethods()) {
MethodGen methodGen = clreplacedContext.getMethodGen(m);
if (methodGen.getName().equals("signRequest")) {
bugReporter.reportBug(//
new BugInstance(this, HARD_CODE_PreplacedWORD_TYPE, Priorities.NORMAL_PRIORITY).addClreplaced(javaClreplaced).addField(new FieldVariable(javaClreplaced.getClreplacedName(), "keyString", "")));
}
}
}
16
Source : ValueNumberDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public ValueNumberDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
throw new MethodUnprofitableException(descriptor);
}
DepthFirstSearch dfs = getDepthFirstSearch(replacedysisCache, descriptor);
LoadedFieldSet loadedFieldSet = getLoadedFieldSet(replacedysisCache, descriptor);
ValueNumberreplacedysis replacedysis = new ValueNumberreplacedysis(methodGen, dfs, loadedFieldSet, replacedysisContext.currentreplacedysisContext().getLookupFailureCallback());
replacedysis.setMergeTree(new MergeTree(replacedysis.getFactory()));
CFG cfg = getCFG(replacedysisCache, descriptor);
ValueNumberDataflow vnaDataflow = new ValueNumberDataflow(cfg, replacedysis);
vnaDataflow.execute();
if (ClreplacedContext.DUMP_DATAFLOW_replacedYSIS) {
TreeSet<Location> tree = new TreeSet<>();
for (Iterator<Location> locs = cfg.locationIterator(); locs.hasNext(); ) {
Location loc = locs.next();
tree.add(loc);
}
System.out.println("\n\nValue number replacedysis for " + descriptor.getName() + descriptor.getSignature() + " {");
for (Location loc : tree) {
System.out.println("\nBefore: " + vnaDataflow.getFactAtLocation(loc));
System.out.println("Location: " + loc);
System.out.println("After: " + vnaDataflow.getFactAfterLocation(loc));
}
System.out.println("}\n");
}
return vnaDataflow;
}
16
Source : LiveLocalStoreDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public LiveLocalStoreDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
return null;
}
CFG cfg = getCFG(replacedysisCache, descriptor);
ReverseDepthFirstSearch rdfs = getReverseDepthFirstSearch(replacedysisCache, descriptor);
LiveLocalStorereplacedysis replacedysis = new LiveLocalStorereplacedysis(methodGen, rdfs, getDepthFirstSearch(replacedysisCache, descriptor));
LiveLocalStoreDataflow dataflow = new LiveLocalStoreDataflow(cfg, replacedysis);
dataflow.execute();
if (ClreplacedContext.DUMP_DATAFLOW_replacedYSIS) {
ClreplacedContext.dumpLiveLocalStoreDataflow(descriptor, cfg, dataflow);
}
return dataflow;
}
16
Source : IsNullValueDataflowFactory.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/*
* (non-Javadoc)
*
* @see
* edu.umd.cs.findbugs.clreplacedfile.IreplacedysisEngine#replacedyze(edu.umd.cs.findbugs
* .clreplacedfile.IreplacedysisCache, java.lang.Object)
*/
@Override
public IsNullValueDataflow replacedyze(IreplacedysisCache replacedysisCache, MethodDescriptor descriptor) throws CheckedreplacedysisException {
MethodGen methodGen = getMethodGen(replacedysisCache, descriptor);
if (methodGen == null) {
throw new MethodUnprofitableException(descriptor);
}
CFG cfg = getCFG(replacedysisCache, descriptor);
ValueNumberDataflow vnaDataflow = getValueNumberDataflow(replacedysisCache, descriptor);
DepthFirstSearch dfs = getDepthFirstSearch(replacedysisCache, descriptor);
replacedertionMethods replacedertionMethods = getreplacedertionMethods(replacedysisCache, descriptor.getClreplacedDescriptor());
TypeDataflow typeDataflow = getTypeDataflow(replacedysisCache, descriptor);
IsNullValuereplacedysis invreplacedysis = new IsNullValuereplacedysis(descriptor, methodGen, cfg, vnaDataflow, typeDataflow, dfs, replacedertionMethods);
// Set return value and parameter databases
invreplacedysis.setClreplacedAndMethod(new JavaClreplacedAndMethod(getJavaClreplaced(replacedysisCache, descriptor.getClreplacedDescriptor()), getMethod(replacedysisCache, descriptor)));
IsNullValueDataflow invDataflow = new IsNullValueDataflow(cfg, invreplacedysis);
invDataflow.execute();
if (ClreplacedContext.DUMP_DATAFLOW_replacedYSIS) {
invDataflow.dumpDataflow(invreplacedysis);
}
return invDataflow;
}
16
Source : ClassContext.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
@Nonnull
static public Set<Integer> getLoopExitBranches(Method method, MethodGen methodGen) {
XMethod xmethod = XFactory.createXMethod(methodGen);
if (cachedLoopExits().containsKey(xmethod)) {
Set<Integer> result = cachedLoopExits().get(xmethod);
if (result == null) {
replacedysisContext.logError("Null cachedLoopExits for " + xmethod, new NullPointerException());
replacedert false;
return Collections.<Integer>emptySet();
}
return result;
}
Code code = method.getCode();
if (code == null) {
replacedert false;
return Collections.<Integer>emptySet();
}
byte[] instructionList = code.getCode();
Set<Integer> result = new HashSet<>();
for (int i = 0; i < instructionList.length; i++) {
if (checkForBranchExit(instructionList, i)) {
result.add(i);
}
}
if (result.size() == 0) {
result = Collections.<Integer>emptySet();
}
cachedLoopExits().put(xmethod, result);
return result;
}
16
Source : BetterCFGBuilder2.java
with GNU Lesser General Public License v2.1
from spotbugs
with GNU Lesser General Public License v2.1
from spotbugs
/**
* Test driver.
*/
public static void main(String[] argv) throws Exception {
if (argv.length != 1) {
System.err.println("Usage: " + BetterCFGBuilder2.clreplaced.getName() + " <clreplaced file>");
System.exit(1);
}
String methodName = SystemProperties.getProperty("cfgbuilder.method");
JavaClreplaced jclreplaced = new ClreplacedParser(argv[0]).parse();
ClreplacedGen clreplacedGen = new ClreplacedGen(jclreplaced);
Method[] methodList = jclreplaced.getMethods();
for (Method method : methodList) {
if (method.isAbstract() || method.isNative()) {
continue;
}
if (methodName != null && !method.getName().equals(methodName)) {
continue;
}
MethodDescriptor descriptor = DescriptorFactory.instance().getMethodDescriptor(jclreplaced, method);
MethodGen methodGen = new MethodGen(method, jclreplaced.getClreplacedName(), clreplacedGen.getConstantPool());
CFGBuilder cfgBuilder = new BetterCFGBuilder2(descriptor, methodGen);
cfgBuilder.build();
CFG cfg = cfgBuilder.getCFG();
CFGPrinter cfgPrinter = new CFGPrinter(cfg);
System.out.println("---------------------------------------------------------------------");
System.out.println("Method: " + SignatureConverter.convertMethodSignature(methodGen));
System.out.println("---------------------------------------------------------------------");
cfgPrinter.print(System.out);
}
}
See More Examples