IsNullValueFrameModelingVisitor.java
| Index Score | ||
|---|---|---|
![]() |
![]() |
edu.umd.cs.findbugs.ba.npe |
![]() |
![]() |
FindBugs |
View: Reasons, Metrics, Source Code
These are the metrics that contribute to the Enerjy Score for this file, ranked by impact. So the metrics listed at the top influence the score to a greater extent that the metrics listed at the bottom.
/*
* Bytecode Analysis Framework
* Copyright (C) 2003-2005 University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.umd.cs.findbugs.ba.npe;
import java.util.Map;
import org.apache.bcel.generic.ACONST_NULL;
import org.apache.bcel.generic.ANEWARRAY;
import org.apache.bcel.generic.CHECKCAST;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETFIELD;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.INVOKEINTERFACE;
import org.apache.bcel.generic.INVOKESPECIAL;
import org.apache.bcel.generic.INVOKESTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.Instruction;
import org.apache.bcel.generic.InvokeInstruction;
import org.apache.bcel.generic.LDC;
import org.apache.bcel.generic.LDC2_W;
import org.apache.bcel.generic.MULTIANEWARRAY;
import org.apache.bcel.generic.NEW;
import org.apache.bcel.generic.NEWARRAY;
import org.apache.bcel.generic.PUTFIELD;
import org.apache.bcel.generic.ReferenceType;
import org.apache.bcel.generic.Type;
import edu.umd.cs.findbugs.SystemProperties;
import edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor;
import edu.umd.cs.findbugs.ba.AnalysisContext;
import edu.umd.cs.findbugs.ba.AssertionMethods;
import edu.umd.cs.findbugs.ba.DataflowAnalysisException;
import edu.umd.cs.findbugs.ba.NullnessAnnotation;
import edu.umd.cs.findbugs.ba.XFactory;
import edu.umd.cs.findbugs.ba.XField;
import edu.umd.cs.findbugs.ba.XMethod;
import edu.umd.cs.findbugs.ba.vna.AvailableLoad;
import edu.umd.cs.findbugs.ba.vna.ValueNumber;
import edu.umd.cs.findbugs.ba.vna.ValueNumberAnalysisFeatures;
import edu.umd.cs.findbugs.ba.vna.ValueNumberDataflow;
import edu.umd.cs.findbugs.ba.vna.ValueNumberFrame;
public class IsNullValueFrameModelingVisitor extends AbstractFrameModelingVisitor<IsNullValue, IsNullValueFrame> {
private static final boolean NO_ASSERT_HACK = SystemProperties.getBoolean("inva.noAssertHack");
private static final boolean MODEL_NONNULL_RETURN = SystemProperties.getBoolean("fnd.modelNonnullReturn",true);
private AssertionMethods assertionMethods;
private ValueNumberDataflow vnaDataflow;
private final boolean trackValueNumbers;
private int slotContainingNewNullValue;
public IsNullValueFrameModelingVisitor(
ConstantPoolGen cpg,
AssertionMethods assertionMethods,
ValueNumberDataflow vnaDataflow,
boolean trackValueNumbers) {
super(cpg);
this.assertionMethods = assertionMethods;
this.vnaDataflow = vnaDataflow;
this.trackValueNumbers = trackValueNumbers;
}
/* (non-Javadoc)
* @see edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor#analyzeInstruction(org.apache.bcel.generic.Instruction)
*/
@Override
public void analyzeInstruction(Instruction ins) throws DataflowAnalysisException {
slotContainingNewNullValue = -1;
super.analyzeInstruction(ins);
if (!NO_ASSERT_HACK) {
if (assertionMethods.isAssertionHandle(getLocation().getHandle(), cpg)) {
IsNullValueFrame frame = getFrame();
for (int i = 0; i < frame.getNumSlots(); ++i) {
IsNullValue value = frame.getValue(i);
if (value.isDefinitelyNull() || value.isNullOnSomePath()) {
frame.setValue(i, IsNullValue.nonReportingNotNullValue());
}
}
for(Map.Entry<ValueNumber,IsNullValue> e : frame.getKnownValueMapEntrySet()) {
IsNullValue value = e.getValue();
if (value.isDefinitelyNull() || value.isNullOnSomePath())
e.setValue(IsNullValue.nonReportingNotNullValue());
}
}
}
}
/**
* @return Returns the slotContainingNewNullValue; or -1 if no new null value
* was produced
*/
public int getSlotContainingNewNullValue() {
return slotContainingNewNullValue;
}
@Override
public IsNullValue getDefaultValue() {
return IsNullValue.nonReportingNotNullValue();
}
// Overrides of specific instruction visitor methods.
// ACONST_NULL obviously produces a value that is DEFINITELY NULL.
// LDC produces values that are NOT NULL.
// NEW produces values that are NOT NULL.
// Note that all instructions that have an implicit null
// check (field access, invoke, etc.) are handled in IsNullValueAnalysis,
// because handling them relies on control flow (the existence of
// an ETB and exception edge prior to the block containing the
// instruction with the null check.)
// Note that we don't override IFNULL and IFNONNULL.
// Those are handled in the analysis itself, because we need
// to produce different values in each of the control successors.
private void produce(IsNullValue value) {
IsNullValueFrame frame = getFrame();
frame.pushValue(value);
newValueOnTOS();
}
private void produce2(IsNullValue value) {
IsNullValueFrame frame = getFrame();
frame.pushValue(value);
frame.pushValue(value);
}
/**
* Handle method invocations.
* Generally, we want to get rid of null information following a
* call to a likely exception thrower or assertion.
*/
private void handleInvoke(InvokeInstruction obj) {
Type callType = obj.getLoadClassType(getCPG());
Type returnType = obj.getReturnType(getCPG());
boolean stringMethodCall = callType.equals(Type.STRING) && returnType.equals(Type.STRING);
// Determine if we are going to model the return value of this call.
boolean modelCallReturnValue = MODEL_NONNULL_RETURN && returnType instanceof ReferenceType;
if( !modelCallReturnValue) {
// Normal case: Assume returned values are non-reporting non-null.
handleNormalInstruction(obj);
} else {
// Special case: some special value is pushed on the stack for the return value
IsNullValue pushValue = null;
if (false && stringMethodCall) {
// String methods always return a non-null value
pushValue = IsNullValue.nonNullValue();
} else {
// Check to see if this method is in either database
XMethod calledMethod = XFactory.createXMethod(obj, getCPG());
if (IsNullValueAnalysis.DEBUG) System.out.println("Check " + calledMethod + " for null return...");
NullnessAnnotation annotation = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase().getResolvedAnnotation(calledMethod, false);
Boolean alwaysNonNull = AnalysisContext.currentAnalysisContext().getReturnValueNullnessPropertyDatabase().getProperty(calledMethod.getMethodDescriptor());
if (annotation == NullnessAnnotation.CHECK_FOR_NULL) {
if (IsNullValueAnalysis.DEBUG) {
System.out.println("Null value returned from " + calledMethod);
}
pushValue = IsNullValue.nullOnSimplePathValue().markInformationAsComingFromReturnValueOfMethod(calledMethod);
} else if (annotation == NullnessAnnotation.NULLABLE) {
pushValue = IsNullValue.nonReportingNotNullValue();
} else if (annotation == NullnessAnnotation.NONNULL || (alwaysNonNull != null && alwaysNonNull.booleanValue())) {
// Method is declared NOT to return null
if (IsNullValueAnalysis.DEBUG) {
System.out.println("NonNull value return from " + calledMethod);
}
pushValue = IsNullValue.nonNullValue().markInformationAsComingFromReturnValueOfMethod(calledMethod);
} else {
pushValue = IsNullValue.nonReportingNotNullValue();
}
}
modelInstruction(obj, getNumWordsConsumed(obj), getNumWordsProduced(obj), pushValue);
newValueOnTOS();
}
}
/**
* Hook indicating that a new (possibly-null) value is on the
* top of the stack.
*/
private void newValueOnTOS() {
IsNullValueFrame frame= getFrame();
if (frame.getStackDepth() < 1) {
return;
}
int tosSlot = frame.getNumSlots() - 1;
IsNullValue tos = frame.getValue(tosSlot);
if (tos.isDefinitelyNull()) {
slotContainingNewNullValue = tosSlot;
}
if (trackValueNumbers) {
try {
ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(getLocation());
if (vnaFrameAfter.isValid()) {
ValueNumber tosVN = vnaFrameAfter.getTopValue();
getFrame().setKnownValue(tosVN, tos);
}
} catch (DataflowAnalysisException e) {
AnalysisContext.logError("error", e);
}
}
}
@Override
public void visitPUTFIELD(PUTFIELD obj) {
if (getNumWordsConsumed(obj) != 2) {
super.visitPUTFIELD(obj);
return;
}
IsNullValue nullValueStored = null;
try {
nullValueStored = getFrame().getTopValue();
} catch (DataflowAnalysisException e1) {
AnalysisContext.logError("Oops", e1);
}
super.visitPUTFIELD(obj);
XField field = XFactory.createXField(obj, cpg);
if (nullValueStored != null && ValueNumberAnalysisFeatures.REDUNDANT_LOAD_ELIMINATION)
try {
ValueNumberFrame vnaFrameBefore = vnaDataflow.getFactAtLocation(getLocation());
ValueNumber refValue = vnaFrameBefore.getStackValue(1);
AvailableLoad load = new AvailableLoad(refValue, field);
ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(getLocation());
ValueNumber [] newValueNumbersForField = vnaFrameAfter.getAvailableLoad(load);
if (newValueNumbersForField != null && trackValueNumbers)
for(ValueNumber v : newValueNumbersForField)
getFrame().setKnownValue(v, nullValueStored);
} catch (DataflowAnalysisException e) {
AnalysisContext.logError("Oops", e);
}
}
@Override
public void visitGETFIELD(GETFIELD obj) {
if (getNumWordsProduced(obj) != 1) {
super.visitGETFIELD(obj);
return;
}
if (checkForKnownValue(obj)) {
return;
}
XField field = XFactory.createXField(obj, cpg);
NullnessAnnotation annotation = AnalysisContext.currentAnalysisContext().getNullnessAnnotationDatabase().getResolvedAnnotation(field, false);
if (annotation == NullnessAnnotation.NONNULL) {
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(IsNullValue.nonNullValue());
}
else if (annotation == NullnessAnnotation.CHECK_FOR_NULL) {
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(IsNullValue.nullOnSimplePathValue().markInformationAsComingFromFieldValue(field));
} else {
super.visitGETFIELD(obj);
}
}
/* (non-Javadoc)
* @see edu.umd.cs.findbugs.ba.AbstractFrameModelingVisitor#visitGETSTATIC(org.apache.bcel.generic.GETSTATIC)
*/
@Override
public void visitGETSTATIC(GETSTATIC obj) {
if (getNumWordsProduced(obj) != 1) {
super.visitGETSTATIC(obj);
return;
}
if (checkForKnownValue(obj)) {
return;
}
XField field = XFactory.createXField(obj, cpg);
if (field.getClassName().equals("java.util.logging.Level")
&& field.getName().equals("SEVERE")
|| field.getClassName().equals("org.apache.log4j.Level")
&& (field.getName().equals("ERROR") || field.getName().equals("FATAL")))
getFrame().toExceptionValues();
if (field.getName().startsWith("class$")) {
produce(IsNullValue.nonNullValue());
return;
}
NullnessAnnotation annotation = AnalysisContext
.currentAnalysisContext().getNullnessAnnotationDatabase()
.getResolvedAnnotation(field, false);
if (annotation == NullnessAnnotation.NONNULL) {
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(IsNullValue.nonNullValue());
} else if (annotation == NullnessAnnotation.CHECK_FOR_NULL) {
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(IsNullValue.nullOnSimplePathValue().markInformationAsComingFromFieldValue(field));
} else {
super.visitGETSTATIC(obj);
}
}
/**
* Check given Instruction to see if it produces a known value.
* If so, model the instruction and return true.
* Otherwise, do nothing and return false.
* Should only be used for instructions that produce a single
* value on the top of the stack.
*
* @param obj the Instruction the instruction
* @return true if the instruction produced a known value and was modeled,
* false otherwise
*/
private boolean checkForKnownValue(Instruction obj) {
if (trackValueNumbers) {
try {
// See if the value number loaded here is a known value
ValueNumberFrame vnaFrameAfter = vnaDataflow.getFactAfterLocation(getLocation());
if (vnaFrameAfter.isValid()) {
ValueNumber tosVN = vnaFrameAfter.getTopValue();
IsNullValue knownValue = getFrame().getKnownValue(tosVN);
if (knownValue != null) {
//System.out.println("Produce known value!");
// The value produced by this instruction is known.
// Push the known value.
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(knownValue);
return true;
}
}
} catch (DataflowAnalysisException e) {
// Ignore...
}
}
return false;
}
@Override
public void visitACONST_NULL(ACONST_NULL obj) {
produce(IsNullValue.nullValue());
}
@Override
public void visitNEW(NEW obj) {
produce(IsNullValue.nonNullValue());
}
@Override
public void visitNEWARRAY(NEWARRAY obj) {
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(IsNullValue.nonNullValue());
}
@Override
public void visitANEWARRAY(ANEWARRAY obj) {
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(IsNullValue.nonNullValue());
}
@Override
public void visitMULTIANEWARRAY(MULTIANEWARRAY obj) {
modelNormalInstruction(obj, getNumWordsConsumed(obj), 0);
produce(IsNullValue.nonNullValue());
}
@Override
public void visitLDC(LDC obj) {
produce(IsNullValue.nonNullValue());
}
@Override
public void visitLDC2_W(LDC2_W obj) {
produce2(IsNullValue.nonNullValue());
}
@Override
public void visitCHECKCAST(CHECKCAST obj) {
// Do nothing
}
@Override
public void visitINVOKESTATIC(INVOKESTATIC obj) {
handleInvoke(obj);
}
@Override
public void visitINVOKESPECIAL(INVOKESPECIAL obj) {
handleInvoke(obj);
}
@Override
public void visitINVOKEINTERFACE(INVOKEINTERFACE obj) {
handleInvoke(obj);
}
@Override
public void visitINVOKEVIRTUAL(INVOKEVIRTUAL obj) {
handleInvoke(obj);
}
}
// vim:ts=4
The table below shows all metrics for IsNullValueFrameModelingVisitor.java.




