private State getTransferState(InstructionHandle handle) { StateSet stateSet; try { stateSet = dataflow.getFactAtLocation(new Location(handle, curBlock)); } catch (DataflowAnalysisException e) { bugReporter.logError("Error checking obligation state at " + handle, e); return null; } List<State> prefixes = stateSet.getPrefixStates(state.getPath()); if (prefixes.size() != 1) { // Could this happen? if (DEBUG_FP) { System.out.println( "at " + handle + " in " + xmethod + " found " + prefixes.size() + " states which are prefixes of error state"); } return null; } return prefixes.get(0); }
public void analyzeMethod() throws CheckedAnalysisException { if (DEBUG_METHOD != null && !methodDescriptor.getName().equals(DEBUG_METHOD)) { return; } if (DEBUG) { System.out.println("*** Analyzing method " + methodDescriptor); } xmethod = XFactory.createXMethod(methodDescriptor); analysisCache = Global.getAnalysisCache(); // // Execute the obligation dataflow analysis // try { dataflow = analysisCache.getMethodAnalysis(ObligationDataflow.class, methodDescriptor); } catch (ObligationAcquiredOrReleasedInLoopException e) { // It is not possible to analyze this method. if (DEBUG) { System.out.println( "FindUnsatisifedObligation: " + methodDescriptor + ": " + e.getMessage()); } return; } // // Additional analyses // needed these to apply the false-positive // suppression heuristics. // cpg = analysisCache.getClassAnalysis( ConstantPoolGen.class, methodDescriptor.getClassDescriptor()); typeDataflow = analysisCache.getMethodAnalysis(TypeDataflow.class, methodDescriptor); subtypes2 = Global.getAnalysisCache().getDatabase(Subtypes2.class); // // Main loop: looking at the StateSet at the exit block of the CFG, // see if there are any states with nonempty obligation sets. // Map<Obligation, State> leakedObligationMap = new HashMap<Obligation, State>(); StateSet factAtExit = dataflow.getResultFact(cfg.getExit()); for (Iterator<State> i = factAtExit.stateIterator(); i.hasNext(); ) { State state = i.next(); checkStateForLeakedObligations(state, leakedObligationMap); } // // Report a separate BugInstance for each Obligation,State pair. // (Two different obligations may be leaked in the same state.) // for (Map.Entry<Obligation, State> entry : leakedObligationMap.entrySet()) { Obligation obligation = entry.getKey(); State state = entry.getValue(); reportWarning(obligation, state, factAtExit); } // TODO: closing of nonexistent resources }
private void reportWarning(Obligation obligation, State state, StateSet factAtExit) { String className = obligation.getClassName(); if (methodDescriptor.isStatic() && methodDescriptor.getName().equals("main") && methodDescriptor.getSignature().equals("([Ljava/lang/String;)V") && (className.contains("InputStream") || className.contains("Reader") || factAtExit.isOnExceptionPath())) { // Don't report unclosed input streams and readers in main() // methods return; } String bugPattern = factAtExit.isOnExceptionPath() ? "OBL_UNSATISFIED_OBLIGATION_EXCEPTION_EDGE" : "OBL_UNSATISFIED_OBLIGATION"; BugInstance bugInstance = new BugInstance(FindUnsatisfiedObligation.this, bugPattern, NORMAL_PRIORITY) .addClassAndMethod(methodDescriptor) .addClass(className) .describe("CLASS_REFTYPE"); // Report how many instances of the obligation are remaining bugInstance .addInt(state.getObligationSet().getCount(obligation.getId())) .describe(IntAnnotation.INT_OBLIGATIONS_REMAINING); // Add source line information annotateWarningWithSourceLineInformation(state, obligation, bugInstance); if (REPORT_OBLIGATION_SET) { bugInstance .addString(state.getObligationSet().toString()) .describe(StringAnnotation.REMAINING_OBLIGATIONS_ROLE); } bugReporter.reportBug(bugInstance); }