public ConstantAnalysis(MethodGen methodGen, DepthFirstSearch dfs) { super(dfs); this.methodGen = methodGen; this.visitor = new ConstantFrameModelingVisitor(methodGen.getConstantPool()); }
/** * Return whether or not given instruction is an assertion. * * @param handle * the instruction * @return true if instruction is an assertion, false otherwise */ private boolean isAssertion(InstructionHandle handle) { return assertionMethods.isAssertionHandle(handle, methodGen.getConstantPool()); }
/** * Constructor. * * @param methodGen * the method being analyzed * @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 class 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<>(); }
/** * Add a method annotation for the method which is called by given * instruction. * * @param methodGen * the method containing the call * @param inv * the InvokeInstruction * @return this object */ @Nonnull public BugInstance addCalledMethod(MethodGen methodGen, InvokeInstruction inv) { ConstantPoolGen cpg = methodGen.getConstantPool(); return addCalledMethod(cpg, inv); }
public ResourceValueAnalysis(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); }
/** * 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 DataflowAnalysisException */ private void checkUnconditionalDerefDatabase(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { ConstantPoolGen constantPool = methodGen.getConstantPool(); for (ValueNumber vn : checkUnconditionalDerefDatabase(location, vnaFrame, constantPool, invDataflow.getFactAtLocation(location), typeDataflow)) { 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 DataflowAnalysisException */ private void checkNonNullParams(Location location, ValueNumberFrame vnaFrame, UnconditionalValueDerefSet fact) throws DataflowAnalysisException { ConstantPoolGen constantPool = methodGen.getConstantPool(); Set<ValueNumber> nonNullParams = checkNonNullParams(location, vnaFrame, constantPool, method, invDataflow.getFactAtLocation(location)); for (ValueNumber vn : nonNullParams) { fact.addDeref(vn, location); } }
/** * 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(); IAnalysisCache analysisCache = Global.getAnalysisCache(); StandardTypeMerger merger = null; ExceptionSetFactory exceptionSetFactory; try { exceptionSetFactory = analysisCache.getMethodAnalysis(ExceptionSetFactory.class, descriptor); merger = new StandardTypeMerger( AnalysisContext.currentAnalysisContext() .getLookupFailureCallback(), exceptionSetFactory); } catch (CheckedAnalysisException e) { AnalysisContext.logError("Unable to generate exceptionSetFactory for " + descriptor, e); } this.exceptionHandlerMap = new ExceptionHandlerMap(methodGen, merger); this.usedInstructionSet = new BitSet(); this.jsrSubroutineMap = new IdentityHashMap<>(); this.subroutineWorkList = new LinkedList<>(); }
/** * Constructor. * * @param method * TODO * @param methodGen * the MethodGen whose CFG we'll be analyzing * @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 TypeAnalysis(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.getClassName() + "." + methodGen.getName() + " " + methodGen.getSignature()); } }
public IsNullValueAnalysis(MethodDescriptor descriptor, MethodGen methodGen, CFG cfg, ValueNumberDataflow vnaDataflow, TypeDataflow typeDataflow, DepthFirstSearch dfs, AssertionMethods assertionMethods) { super(dfs); this.trackValueNumbers = AnalysisContext.currentAnalysisContext().getBoolProperty( AnalysisFeatures.TRACK_VALUE_NUMBERS_IN_NULL_POINTER_ANALYSIS); this.methodGen = methodGen; this.visitor = new IsNullValueFrameModelingVisitor(methodGen.getConstantPool(), assertionMethods, vnaDataflow, typeDataflow, trackValueNumbers); this.vnaDataflow = vnaDataflow; this.cfg = cfg; this.locationWhereValueBecomesNullSet = new HashSet<>(); this.pointerEqualityCheck = getForPointerEqualityCheck(cfg, vnaDataflow); if (DEBUG) { System.out.println("IsNullValueAnalysis for " + methodGen.getClassName() + "." + methodGen.getName() + " : " + methodGen.getSignature()); } }
public boolean preScreen(MethodGen mg) { ConstantPoolGen cpg = mg.getConstantPool(); int lockCount = mg.isSynchronized() ? 1 : 0; boolean sawWaitOrNotify = false; InstructionHandle handle = mg.getInstructionList().getStart(); while (handle != null && !(lockCount >= 2 && sawWaitOrNotify)) { Instruction ins = handle.getInstruction(); if (ins instanceof MONITORENTER) { ++lockCount; } else if (ins instanceof INVOKEVIRTUAL) { INVOKEVIRTUAL inv = (INVOKEVIRTUAL) ins; String methodName = inv.getMethodName(cpg); if ("wait".equals(methodName) || methodName.startsWith("notify")) { sawWaitOrNotify = true; } } handle = handle.getNext(); } return lockCount >= 2 && sawWaitOrNotify; }
@Override public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, LockSet fact) throws DataflowAnalysisException { 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); } }
/** * Factory method for creating a source line annotation describing the * source line number for a visited instruction. * * @param classContext * the ClassContext * @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(ClassContext classContext, MethodGen methodGen, String sourceFile, @Nonnull InstructionHandle handle) { LineNumberTable table = methodGen.getLineNumberTable(methodGen.getConstantPool()); String className = methodGen.getClassName(); int bytecodeOffset = handle.getPosition(); if (table == null) { return createUnknown(className, sourceFile, bytecodeOffset, bytecodeOffset); } int lineNumber = table.getSourceLine(handle.getPosition()); return new SourceLineAnnotation(className, sourceFile, lineNumber, lineNumber, bytecodeOffset, bytecodeOffset); }
UselessValuesContext(ClassContext classContext, Method method) throws CheckedAnalysisException { this.classContext = classContext; this.method = method; cfg = classContext.getCFG(method); cpg = cfg.getMethodGen().getConstantPool(); ta = classContext.getTypeDataflow(method).getAnalysis(); vna = classContext.getValueNumberDataflow(method).getAnalysis(); }
/** * 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); } return true; // false } if (edge.getType() != EdgeTypes.FALL_THROUGH_EDGE) { return false; } InstructionHandle h = edge.getSource().getLastInstruction(); if (h != null && h.getInstruction() instanceof IFNONNULL && isNullCheck(h, methodGen.getConstantPool())) { return true; } return false; }
/** * 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 className = methodGen.getClassName(); int codeSize = methodGen.getInstructionList().getLength(); if (lineNumberTable == null) { return createUnknown(className, sourceFile, 0, codeSize - 1); } return forEntireMethod(className, sourceFile, lineNumberTable, codeSize); }
private Location getValueNumberCreationLocation(ValueNumberDataflow vnd, ValueNumber vn) { ConstantPoolGen cpg = vnd.getCFG().getMethodGen().getConstantPool(); for(Iterator<Location> it = vnd.getCFG().locationIterator(); it.hasNext(); ) { Location loc = it.next(); if(loc.getHandle().getInstruction().produceStack(cpg) != 1) { continue; } try { ValueNumberFrame vnf = vnd.getFactAfterLocation(loc); if(vnf.getTopValue().equals(vn)) { return loc; } } catch (DataflowAnalysisException e) { AnalysisContext.logError("While analyzing "+vnd.getCFG().getMethodGen()+" at "+loc, e); } } return null; }
public void visitLocation(ClassContext classContext, Location location, MethodGen methodGen, LockDataflow dataflow) throws DataflowAnalysisException { ConstantPoolGen cpg = methodGen.getConstantPool(); if (Hierarchy.isMonitorWait(location.getHandle().getInstruction(), cpg)) { int count = dataflow.getFactAtLocation(location).getNumLockedObjects(); if (count > 1) { // A wait with multiple locks held? String sourceFile = javaClass.getSourceFileName(); possibleWaitBugs.add(new BugInstance(this, "TLW_TWO_LOCK_WAIT", HIGH_PRIORITY).addClassAndMethod(methodGen, sourceFile).addSourceLine(classContext, methodGen, sourceFile, location.getHandle())); } } if (Hierarchy.isMonitorNotify(location.getHandle().getInstruction(), cpg)) { int count = dataflow.getFactAtLocation(location).getNumLockedObjects(); if (count > 1) { // A notify with multiple locks held? String sourceFile = javaClass.getSourceFileName(); possibleNotifyLocations.add(SourceLineAnnotation.fromVisitedInstruction(classContext, methodGen, sourceFile, location.getHandle())); } } }
/** * Factory method for creating a source line annotation describing the * source line numbers for a range of instruction in a method. * * @param classContext * theClassContext * @param methodGen * the method * @param start * the start instruction * @param end * the end instruction (inclusive) */ public static SourceLineAnnotation fromVisitedInstructionRange(ClassContext classContext, MethodGen methodGen, String sourceFile, InstructionHandle start, InstructionHandle end) { LineNumberTable lineNumberTable = methodGen.getLineNumberTable(methodGen.getConstantPool()); String className = methodGen.getClassName(); if (lineNumberTable == null) { return createUnknown(className, sourceFile, start.getPosition(), end.getPosition()); } int startLine = lineNumberTable.getSourceLine(start.getPosition()); int endLine = lineNumberTable.getSourceLine(end.getPosition()); return new SourceLineAnnotation(className, sourceFile, startLine, endLine, start.getPosition(), end.getPosition()); }
private void killLoadsOfObjectsPassed(InvokeInstruction ins) { try { XMethod called = Hierarchy2.findExactMethod(ins, methodGen.getConstantPool(), Hierarchy.ANY_METHOD); if (called != null ) { NoSideEffectMethodsDatabase nse = Global.getAnalysisCache().getOptionalDatabase(NoSideEffectMethodsDatabase.class); if(nse != null && !nse.is(called.getMethodDescriptor(), MethodSideEffectStatus.SE, MethodSideEffectStatus.OBJ)) { return; } } FieldSummary fieldSummary = AnalysisContext.currentAnalysisContext().getFieldSummary(); Set<XField> touched = fieldSummary.getFieldsWritten(called); if (!touched.isEmpty()) { getFrame().killLoadsOf(touched); } int passed = getNumWordsConsumed(ins); ValueNumber[] arguments = allocateValueNumberArray(passed); getFrame().killLoadsWithSimilarName(ins.getClassName(cpg), ins.getMethodName(cpg)); getFrame().getTopStackWords(arguments); for (ValueNumber v : arguments) { getFrame().killAllLoadsOf(v); } // Too many false-positives for primitives without transitive FieldSummary analysis, // so currently we simply kill any writable primitive on any method call // TODO: implement transitive FieldSummary getFrame().killAllLoads(true); } catch (DataflowAnalysisException e) { AnalysisContext.logError("Error in killLoadsOfObjectsPassed", e); } }