1 20 21 package edu.umd.cs.findbugs.detect; 22 23 24 import edu.umd.cs.findbugs.*; 25 import edu.umd.cs.findbugs.ba.*; 26 import edu.umd.cs.findbugs.classfile.MethodDescriptor; 27 28 import java.util.*; 29 import org.apache.bcel.Repository; 30 import org.apache.bcel.classfile.*; 31 import org.apache.bcel.generic.*; 32 ; 33 34 41 public class RuntimeExceptionCapture extends BytecodeScanningDetector implements Detector, StatelessDetector { 42 private static final boolean DEBUG = SystemProperties.getBoolean("rec.debug"); 43 44 private BugReporter bugReporter; 45 private Method method; 46 private OpcodeStack stack = new OpcodeStack(); 47 private List<ExceptionCaught> catchList; 48 private List<ExceptionThrown> throwList; 49 50 private BugAccumulator accumulator; 51 private static class ExceptionCaught { 52 public String exceptionClass; 53 public int startOffset, endOffset, sourcePC; 54 public boolean seen = false; 55 public boolean dead = false; 56 57 public ExceptionCaught(String exceptionClass, int startOffset, int endOffset, int sourcePC) { 58 this.exceptionClass = exceptionClass; 59 this.startOffset = startOffset; 60 this.endOffset = endOffset; 61 this.sourcePC = sourcePC; 62 } 63 } 64 65 private static class ExceptionThrown { 66 public String exceptionClass; 67 public int offset; 68 69 public ExceptionThrown(String exceptionClass, int offset) { 70 this.exceptionClass = exceptionClass; 71 this.offset = offset; 72 } 73 } 74 75 76 public RuntimeExceptionCapture(BugReporter bugReporter) { 77 this.bugReporter = bugReporter; 78 accumulator = new BugAccumulator(bugReporter); 79 } 80 81 82 83 @Override 84 public void visitMethod(Method method) { 85 this.method = method; 86 if (DEBUG) { 87 System.out.println("RuntimeExceptionCapture visiting " + method); 88 } 89 super.visitMethod(method); 90 accumulator.reportAccumulatedBugs(); 91 } 92 93 @Override 94 public void visitCode(Code obj) { 95 catchList = new ArrayList<ExceptionCaught>(); 96 throwList = new ArrayList<ExceptionThrown>(); 97 stack.resetForMethodEntry(this); 98 99 super.visitCode(obj); 100 101 for (ExceptionCaught caughtException : catchList) { 102 Set<String > thrownSet = new HashSet<String >(); 103 for (ExceptionThrown thrownException : throwList) { 104 if (thrownException.offset >= caughtException.startOffset 105 && thrownException.offset < caughtException.endOffset) { 106 thrownSet.add(thrownException.exceptionClass); 107 if (thrownException.exceptionClass.equals(caughtException.exceptionClass)) 108 caughtException.seen = true; 109 } 110 } 111 int catchClauses = 0; 112 if (caughtException.exceptionClass.equals("java.lang.Exception") && !caughtException.seen) { 113 boolean rteCaught = false; 115 for (ExceptionCaught otherException : catchList) { 116 if (otherException.startOffset == caughtException.startOffset 117 && otherException.endOffset == caughtException.endOffset) { 118 catchClauses++; 119 if (otherException.exceptionClass.equals("java.lang.RuntimeException")) 120 rteCaught = true; 121 } 122 } 123 int range = caughtException.endOffset - caughtException.startOffset; 124 if (!rteCaught) { 125 int priority = LOW_PRIORITY + 1; 126 if (range > 300) priority--; 127 else if (range < 30) priority++; 128 if (catchClauses > 1) priority++; 129 if (thrownSet.size() > 1) priority--; 130 if (caughtException.dead) priority--; 131 accumulator.accumulateBug(new BugInstance(this, "REC_CATCH_EXCEPTION", 132 priority) 133 .addClassAndMethod(this), 134 SourceLineAnnotation.fromVisitedInstruction(getClassContext(), this, caughtException.sourcePC)); 135 } 136 } 137 } 138 } 139 140 @Override 141 public void visit(CodeException obj) { 142 super.visit(obj); 143 int type = obj.getCatchType(); 144 if (type == 0) return; 145 String name = getConstantPool().constantToString(getConstantPool().getConstant(type)); 146 147 ExceptionCaught caughtException = 148 new ExceptionCaught(name, obj.getStartPC(), obj.getEndPC(), obj.getHandlerPC()); 149 catchList.add(caughtException); 150 151 try { 152 LiveLocalStoreDataflow dataflow = getClassContext().getLiveLocalStoreDataflow(this.method); 157 CFG cfg = getClassContext().getCFG(method); 158 Collection<BasicBlock> blockList = cfg.getBlocksContainingInstructionWithOffset(obj.getHandlerPC()); 159 for (BasicBlock block : blockList) { 160 InstructionHandle first = block.getFirstInstruction(); 161 if (first != null 162 && first.getPosition() == obj.getHandlerPC() 163 && first.getInstruction() instanceof ASTORE) { 164 ASTORE astore = (ASTORE) first.getInstruction(); 165 BitSet liveStoreSet = dataflow.getFactAtLocation(new Location(first, block)); 166 if (!liveStoreSet.get(astore.getIndex())) { 167 if (DEBUG) { 169 System.out.println("Dead exception store at " + first); 170 } 171 caughtException.dead = true; 172 break; 173 } 174 } 175 } 176 } catch (MethodUnprofitableException e) { 177 Method m = getMethod(); 178 bugReporter.reportSkippedAnalysis(new MethodDescriptor(getClassName(), getMethodName(), getMethodSig(), m.isStatic())); 179 } catch (DataflowAnalysisException e) { 180 bugReporter.logError("Error checking for dead exception store", e); 181 } catch (CFGBuilderException e) { 182 bugReporter.logError("Error checking for dead exception store", e); 183 } 184 } 185 186 @Override 187 public void sawOpcode(int seen) { 188 stack.mergeJumps(this); 189 try { 190 switch (seen) { 191 case ATHROW: 192 if (stack.getStackDepth() > 0) { 193 OpcodeStack.Item item = stack.getStackItem(0); 194 String signature = item.getSignature(); 195 if (signature != null && signature.length() > 0) { 196 if (signature.startsWith("L")) 197 signature = SignatureConverter.convert(signature); 198 else 199 signature = signature.replace('/', '.'); 200 throwList.add(new ExceptionThrown(signature, getPC())); 201 } 202 } 203 break; 204 205 case INVOKEVIRTUAL: 206 case INVOKESPECIAL: 207 case INVOKESTATIC: 208 String className = getDottedClassConstantOperand(); 209 try { 210 if (!className.startsWith("[")) { 211 JavaClass clazz = Repository.lookupClass(className); 212 Method[] methods = clazz.getMethods(); 213 for (Method method : methods) { 214 if (method.getName().equals(getNameConstantOperand()) 215 && method.getSignature().equals(getSigConstantOperand())) { 216 ExceptionTable et = method.getExceptionTable(); 217 if (et != null) { 218 String [] names = et.getExceptionNames(); 219 for (String name : names) 220 throwList.add(new ExceptionThrown(name, getPC())); 221 } 222 break; 223 } 224 } 225 } 226 } catch (ClassNotFoundException e) { 227 bugReporter.reportMissingClass(e); 228 } 229 break; 230 default: 231 break; 232 } 233 } finally { 234 stack.sawOpcode(this, seen); 235 } 236 } 237 238 } 239 240 | Popular Tags |