1 19 20 package edu.umd.cs.findbugs.detect; 21 22 import java.util.ArrayList ; 23 import java.util.BitSet ; 24 25 import org.apache.bcel.Constants; 26 import org.apache.bcel.classfile.JavaClass; 27 import org.apache.bcel.classfile.Method; 28 import org.apache.bcel.generic.ConstantPoolGen; 29 import org.apache.bcel.generic.InstructionHandle; 30 import org.apache.bcel.generic.InvokeInstruction; 31 import org.apache.bcel.generic.MethodGen; 32 33 import edu.umd.cs.findbugs.AnalysisLocal; 34 import edu.umd.cs.findbugs.BugInstance; 35 import edu.umd.cs.findbugs.BugReporter; 36 import edu.umd.cs.findbugs.ByteCodePatternDetector; 37 import edu.umd.cs.findbugs.JavaVersion; 38 import edu.umd.cs.findbugs.StatelessDetector; 39 import edu.umd.cs.findbugs.SystemProperties; 40 import edu.umd.cs.findbugs.ba.ClassContext; 41 import edu.umd.cs.findbugs.ba.bcp.ByteCodePattern; 42 import edu.umd.cs.findbugs.ba.bcp.ByteCodePatternMatch; 43 import edu.umd.cs.findbugs.ba.bcp.Invoke; 44 import edu.umd.cs.findbugs.ba.bcp.MatchAny; 45 import edu.umd.cs.findbugs.ba.bcp.Opcode; 46 import edu.umd.cs.findbugs.ba.bcp.PatternElement; 47 48 56 public @Deprecated class BCPMethodReturnCheck extends ByteCodePatternDetector { 57 private final BugReporter bugReporter; 58 59 private static final boolean CHECK_ALL = SystemProperties.getBoolean("mrc.checkall"); 60 61 private static AnalysisLocal<ByteCodePattern> localByteCodePattern 62 = new AnalysisLocal<ByteCodePattern>(); 63 64 private static AnalysisLocal<ArrayList <PatternElement>> localPatternElementList 65 = new AnalysisLocal<ArrayList <PatternElement>>(); 66 67 68 69 70 @Override 71 public ByteCodePattern getPattern() { 72 ByteCodePattern result = localByteCodePattern.get(); 73 if (result == null) { 74 ArrayList <PatternElement> list = getPatternElementList(); 75 PatternElement [] calls = list.toArray(new PatternElement[list.size()]); 76 result = new ByteCodePattern() 80 .add(new MatchAny(calls).label("call").setAllowTrailingEdges(false)) 81 .add(new MatchAny(new PatternElement[]{new Opcode(Constants.POP), new Opcode(Constants.POP2)})); 82 localByteCodePattern.set(result); 83 } 84 return result; 85 } 86 87 public static void 88 addMethodWhoseReturnMustBeChecked(String className, String methodName, 89 String methodSig, int mode) { 90 ArrayList <PatternElement> list = getPatternElementList(); 91 list.add(new Invoke(className, methodName, methodSig, mode, null)); 92 localByteCodePattern.remove(); 93 } 94 95 99 private static 100 ArrayList <PatternElement> getPatternElementList() { 101 ArrayList <PatternElement> list = localPatternElementList.get(); 102 if (list != null) return list; 103 104 list = new ArrayList <PatternElement>(); 105 106 list.add(new Invoke("/.*", "equals", 108 "/\\(Ljava/lang/Object;\\)Z", 109 Invoke.INSTANCE, null)); 110 list.add(new Invoke("java.lang.String", "/.*", 111 "/\\(.*\\)Ljava/lang/String;", 112 Invoke.INSTANCE, null)); 113 list.add(new Invoke("java.lang.StringBuffer", "toString", 114 "()Ljava/lang/String;", 115 Invoke.INSTANCE, 116 null)); 117 list.add(new Invoke("+java.lang.Thread", "<init>", 118 "/.*", 119 Invoke.CONSTRUCTOR, 120 null)); 121 list.add(new Invoke("+java.lang.Throwable", "<init>", 122 "/.*", 123 Invoke.CONSTRUCTOR, 124 null)); 125 list.add(new Invoke("java.security.MessageDigest", 126 "digest", "([B)[B", 127 Invoke.INSTANCE, null)); 128 list.add(new Invoke("+java.sql.Connection", "/.*", "/.*", 129 Invoke.INSTANCE, null)); 130 list.add(new Invoke("java.math.BigDecimal", "/.*", "/.*", 133 Invoke.INSTANCE, null)); 134 list.add(new Invoke("java.math.BigInteger", "/.*", "/.*", 135 Invoke.INSTANCE, null)); 136 list.add(new Invoke("+java.util.Enumeration", "hasMoreElements", "()Z", Invoke.INSTANCE, null)); 137 list.add(new Invoke("+java.util.Iterator", "hasNext", "()Z", Invoke.INSTANCE, null)); 138 list.add(new Invoke("java.io.File", "createNewFile", "()Z", Invoke.INSTANCE, null)); 139 140 if (CHECK_ALL || 141 JavaVersion.getRuntimeVersion().isSameOrNewerThan(JavaVersion.JAVA_1_5)) { 142 list.add(new Invoke("+java.util.concurrent.locks.ReadWriteLock", 144 "readLock", 145 "()Ljava/util/concurrent/locks/Lock;", 146 Invoke.INSTANCE, 147 null)); 148 list.add(new Invoke("+java.util.concurrent.locks.ReadWriteLock", 149 "writeLock", 150 "()Ljava/util/concurrent/locks/Lock;", 151 Invoke.INSTANCE, 152 null)); 153 list.add(new Invoke("+java.util.concurrent.locks.Condition", 154 "await", 155 "(JLjava/util/concurrent/TimeUnit;)Z", 156 Invoke.INSTANCE, 157 null)); 158 list.add(new Invoke("+java.util.concurrent.locks.Condition", 159 "awaitUtil", 160 "(Ljava/util/Date;)Z", 161 Invoke.INSTANCE, 162 null)); 163 list.add(new Invoke("+java.util.concurrent.locks.Condition", 164 "awaitNanos", 165 "(J)Z", 166 Invoke.INSTANCE, 167 null)); 168 list.add(new Invoke("+java.util.concurrent.Semaphore", 169 "tryAcquire", 170 "(JLjava/util/concurrent/TimeUnit;)Z", 171 Invoke.INSTANCE, 172 null)); 173 list.add(new Invoke("+java.util.concurrent.Semaphore", 174 "tryAcquire", 175 "()Z", 176 Invoke.INSTANCE, 177 null)); 178 list.add(new Invoke("+java.util.concurrent.locks.Lock", 179 "tryLock", 180 "(JLjava/util/concurrent/TimeUnit;)Z", 181 Invoke.INSTANCE, 182 null)); 183 list.add(new Invoke("+java.util.concurrent.locks.Lock", 184 "newCondition", 185 "()Ljava/util/concurrent/locks/Condition;", 186 Invoke.INSTANCE, 187 null)); 188 list.add(new Invoke("+java.util.concurrent.locks.Lock", 189 "tryLock", 190 "()Z", 191 Invoke.INSTANCE, 192 null)); 193 list.add(new Invoke("+java.util.Queue", 194 "offer", 195 "(Ljava/lang/Object;)Z", 196 Invoke.INSTANCE, 197 null)); 198 list.add(new Invoke("+java.util.concurrent.BlockingQueue", 199 "offer", 200 "(Ljava/lang/Object;JLjava/util/concurrent/TimeUnit;)Z", 201 Invoke.INSTANCE, 202 null)); 203 list.add(new Invoke("+java.util.concurrent.BlockingQueue", 204 "poll", 205 "(JLjava/util/concurrent/TimeUnit;)Ljava/lang/Object;", 206 Invoke.INSTANCE, 207 null)); 208 list.add(new Invoke("+java.util.Queue", 209 "poll", 210 "()Ljava/lang/Object;", 211 Invoke.INSTANCE, 212 null)); 213 } 214 215 216 String externalCheckReturnValues = SystemProperties.getProperty("checkReturnValues"); 217 if (externalCheckReturnValues != null) { 218 String [] checks = externalCheckReturnValues.split("[|]"); 219 for (String check : checks) { 220 String [] parts = check.split(":"); 221 if (parts.length != 3) continue; 222 Invoke in = 223 new Invoke(parts[0], parts[1], parts[2], Invoke.INSTANCE, null); 224 list.add(in); 225 } 226 } 227 228 229 localPatternElementList.set(list); 230 return list; 231 } 232 233 238 public BCPMethodReturnCheck(BugReporter bugReporter) { 239 this.bugReporter = bugReporter; 240 241 } 242 243 @Override 245 protected BugReporter getBugReporter() { 246 return bugReporter; 247 } 248 249 250 @Override 251 public boolean prescreen(Method method, ClassContext classContext) { 252 BitSet bytecodeSet = classContext.getBytecodeSet(method); 255 return bytecodeSet != null && (bytecodeSet.get(Constants.POP) || bytecodeSet.get(Constants.POP2)); 256 } 257 258 @Override 259 public void reportMatch(ClassContext classContext, Method method, ByteCodePatternMatch match) { 260 MethodGen methodGen = classContext.getMethodGen(method); 261 if (methodGen == null) return; 262 JavaClass javaClass = classContext.getJavaClass(); 263 264 InstructionHandle call = match.getLabeledInstruction("call"); 265 266 InvokeInstruction inv = (InvokeInstruction) call.getInstruction(); 268 ConstantPoolGen cp = methodGen.getConstantPool(); 269 String calledMethodName = inv.getMethodName(cp); 270 if (calledMethodName.startsWith("access$") 271 || calledMethodName.startsWith("access+")) 272 return; 273 274 279 String calledMethodClass = inv.getClassName(cp); 280 if (inv.getSignature(cp).endsWith("V") && !calledMethodName.equals("<init>")) 281 return; 282 286 String sourceFile = javaClass.getSourceFileName(); 287 291 int priority = HIGH_PRIORITY; 292 if (calledMethodName.equals("createNewFile")) 293 priority = LOW_PRIORITY; 294 295 if ( calledMethodClass.startsWith("java.lang") 296 || calledMethodClass.startsWith("java.math") 297 || calledMethodClass.endsWith("Error") 298 || calledMethodClass.endsWith("Exception")) 299 priority--; 300 if (calledMethodClass.equals(javaClass.getClassName())) 301 priority++; 302 String calledPackage = extractPackageName(calledMethodClass); 303 String callingPackage = extractPackageName(javaClass.getClassName()); 304 if (calledPackage.length() > 0 305 && callingPackage.length() > 0 306 && (calledPackage.startsWith(callingPackage) 307 || callingPackage.startsWith(calledPackage))) 308 priority++; 309 311 bugReporter.reportBug(new BugInstance(this, "RV_RETURN_VALUE_IGNORED2", 312 priority) 313 .addClassAndMethod(methodGen, sourceFile) 314 .addCalledMethod(methodGen, inv) 315 .addSourceLine(classContext, methodGen, sourceFile, call)); 316 } 317 318 public static String extractPackageName(String className) { 319 int i = className.lastIndexOf('.'); 320 if (i == -1) return ""; 321 return className.substring(0, i); 322 } 323 324 } 325 326 | Popular Tags |