1 19 20 package edu.umd.cs.findbugs.detect; 21 22 import java.util.Arrays ; 23 import java.util.BitSet ; 24 import java.util.HashSet ; 25 import java.util.Iterator ; 26 import java.util.List ; 27 import java.util.Set ; 28 29 import org.apache.bcel.Constants; 30 import org.apache.bcel.classfile.JavaClass; 31 import org.apache.bcel.classfile.LocalVariable; 32 import org.apache.bcel.classfile.LocalVariableTable; 33 import org.apache.bcel.classfile.Method; 34 import org.apache.bcel.generic.ACONST_NULL; 35 import org.apache.bcel.generic.ALOAD; 36 import org.apache.bcel.generic.ANEWARRAY; 37 import org.apache.bcel.generic.ASTORE; 38 import org.apache.bcel.generic.ConstantPushInstruction; 39 import org.apache.bcel.generic.GETFIELD; 40 import org.apache.bcel.generic.IINC; 41 import org.apache.bcel.generic.INVOKESPECIAL; 42 import org.apache.bcel.generic.IndexedInstruction; 43 import org.apache.bcel.generic.Instruction; 44 import org.apache.bcel.generic.InstructionHandle; 45 import org.apache.bcel.generic.LDC; 46 import org.apache.bcel.generic.LoadInstruction; 47 import org.apache.bcel.generic.MULTIANEWARRAY; 48 import org.apache.bcel.generic.MethodGen; 49 import org.apache.bcel.generic.NEWARRAY; 50 import org.apache.bcel.generic.StoreInstruction; 51 52 import edu.umd.cs.findbugs.BugAccumulator; 53 import edu.umd.cs.findbugs.BugInstance; 54 import edu.umd.cs.findbugs.BugReporter; 55 import edu.umd.cs.findbugs.Detector; 56 import edu.umd.cs.findbugs.FindBugsAnalysisFeatures; 57 import edu.umd.cs.findbugs.LocalVariableAnnotation; 58 import edu.umd.cs.findbugs.SourceLineAnnotation; 59 import edu.umd.cs.findbugs.SystemProperties; 60 import edu.umd.cs.findbugs.ba.CFG; 61 import edu.umd.cs.findbugs.ba.CFGBuilderException; 62 import edu.umd.cs.findbugs.ba.ClassContext; 63 import edu.umd.cs.findbugs.ba.Dataflow; 64 import edu.umd.cs.findbugs.ba.DataflowAnalysisException; 65 import edu.umd.cs.findbugs.ba.LiveLocalStoreAnalysis; 66 import edu.umd.cs.findbugs.ba.Location; 67 import edu.umd.cs.findbugs.props.WarningPropertySet; 68 import edu.umd.cs.findbugs.props.WarningPropertyUtil; 69 import edu.umd.cs.findbugs.visitclass.PreorderVisitor; 70 71 77 public class FindDeadLocalStores implements Detector { 78 79 private static final boolean DEBUG = SystemProperties.getBoolean("fdls.debug"); 80 81 private static final String FINDBUGS_EXCLUDED_LOCALS_PROP_NAME = "findbugs.dls.exclusions"; 84 85 private static final Set <String > EXCLUDED_LOCALS = new HashSet <String >(); 87 88 private static final boolean DO_EXCLUDE_LOCALS = 89 SystemProperties.getProperty(FINDBUGS_EXCLUDED_LOCALS_PROP_NAME) != null; 90 static { 91 String exclLocalsProperty = SystemProperties.getProperty(FINDBUGS_EXCLUDED_LOCALS_PROP_NAME); 93 94 if (exclLocalsProperty != null) { 96 EXCLUDED_LOCALS.addAll( (List <String >)Arrays.asList(exclLocalsProperty.split(","))); 97 EXCLUDED_LOCALS.remove(""); 98 } 99 } 100 101 106 private static final BitSet defensiveConstantValueOpcodes = new BitSet (); 107 static { 108 defensiveConstantValueOpcodes.set(Constants.DCONST_0); 109 defensiveConstantValueOpcodes.set(Constants.DCONST_1); 110 defensiveConstantValueOpcodes.set(Constants.FCONST_0); 111 defensiveConstantValueOpcodes.set(Constants.FCONST_1); 112 defensiveConstantValueOpcodes.set(Constants.ACONST_NULL); 113 defensiveConstantValueOpcodes.set(Constants.ICONST_0); 114 defensiveConstantValueOpcodes.set(Constants.ICONST_1); 115 } 116 117 private BugReporter bugReporter; 118 119 public FindDeadLocalStores(BugReporter bugReporter) { 120 this.bugReporter = bugReporter; 121 if (DEBUG) System.out.println("Debugging FindDeadLocalStores detector"); 122 } 123 124 private boolean prescreen(ClassContext classContext, Method method) { 125 return true; 126 } 127 128 public void visitClassContext(ClassContext classContext) { 129 JavaClass javaClass = classContext.getJavaClass(); 130 Method[] methodList = javaClass.getMethods(); 131 132 for (Method method : methodList) { 133 MethodGen methodGen = classContext.getMethodGen(method); 134 if (methodGen == null) 135 continue; 136 137 if (!prescreen(classContext, method)) 138 continue; 139 140 try { 141 analyzeMethod(classContext, method); 142 } catch (DataflowAnalysisException e) { 143 bugReporter.logError("Error analyzing " + method.toString(), e); 144 } catch (CFGBuilderException e) { 145 bugReporter.logError("Error analyzing " + method.toString(), e); 146 } 147 } 148 } 149 150 private void analyzeMethod(ClassContext classContext, Method method) 151 throws DataflowAnalysisException, CFGBuilderException { 152 153 if (DEBUG) { 154 System.out.println(" Analyzing method " + classContext.getJavaClass().getClassName() + "." + method.getName()); 155 } 156 157 JavaClass javaClass = classContext.getJavaClass(); 158 159 BugAccumulator accumulator = new BugAccumulator(bugReporter); 160 Dataflow<BitSet , LiveLocalStoreAnalysis> llsaDataflow = 161 classContext.getLiveLocalStoreDataflow(method); 162 163 int numLocals = method.getCode().getMaxLocals(); 164 int [] localStoreCount = new int[numLocals]; 165 int [] localLoadCount = new int[numLocals]; 166 int [] localIncrementCount = new int[numLocals]; 167 MethodGen methodGen = classContext.getMethodGen(method); 168 CFG cfg = classContext.getCFG(method); 169 BitSet liveStoreSetAtEntry = llsaDataflow.getAnalysis().getResultFact(cfg.getEntry()); 170 BitSet complainedAbout = new BitSet (); 171 172 int localsThatAreParameters = PreorderVisitor.getNumberArguments(method.getSignature()); 174 if (!method.isStatic()) localsThatAreParameters++; 175 176 countLocalStoresLoadsAndIncrements( 179 localStoreCount, localLoadCount, localIncrementCount, cfg); 180 181 for (Iterator <Location> i = cfg.locationIterator(); i.hasNext(); ) { 185 Location location = i.next(); 186 187 BugInstance pendingBugReportAboutOverwrittenParameter = null; 188 try { 189 WarningPropertySet propertySet = new WarningPropertySet(); 190 if (!isStore(location)) 192 continue; 193 194 if (location.getBasicBlock().isExceptionHandler()) 197 propertySet.addProperty(DeadLocalStoreProperty.EXCEPTION_HANDLER); 198 199 IndexedInstruction ins = (IndexedInstruction) location.getHandle().getInstruction(); 200 201 202 LocalVariableAnnotation lvAnnotation 203 = LocalVariableAnnotation.getLocalVariableAnnotation(method, location, ins); 204 205 String name = lvAnnotation.getName(); 206 if (name.charAt(0) == '$' || name.charAt(0) == '_') propertySet.addProperty(DeadLocalStoreProperty.SYNTHETIC_NAME); 207 if (EXCLUDED_LOCALS.contains(name)) continue; 208 propertySet.setProperty(DeadLocalStoreProperty.LOCAL_NAME, name); 209 210 int local = ins.getIndex(); 211 boolean parameterThatIsDeadAtEntry = local < localsThatAreParameters 213 && !llsaDataflow.getAnalysis().isStoreAlive(liveStoreSetAtEntry, local); 214 if (parameterThatIsDeadAtEntry && !complainedAbout.get(local)) { 215 216 217 218 pendingBugReportAboutOverwrittenParameter = new BugInstance(this, "IP_PARAMETER_IS_DEAD_BUT_OVERWRITTEN", NORMAL_PRIORITY) 220 .addClassAndMethod(methodGen, javaClass.getSourceFileName()) 221 .add(lvAnnotation) 222 .addSourceLine(classContext, methodGen, javaClass.getSourceFileName(), location.getHandle()); 223 complainedAbout.set(local); 224 } 225 226 boolean storeOfNull = false; 227 InstructionHandle prevInsHandle = location.getHandle().getPrev(); 228 if (prevInsHandle != null) { 229 Instruction prevIns = prevInsHandle.getInstruction(); 230 if (prevIns instanceof LDC || prevIns instanceof ConstantPushInstruction) 231 continue; 232 if ( prevIns instanceof ACONST_NULL) { 233 storeOfNull = true; 234 propertySet.addProperty(DeadLocalStoreProperty.STORE_OF_NULL); 235 } 236 237 } 238 239 BitSet liveStoreSet = llsaDataflow.getAnalysis().getFactAtLocation(location); 243 244 if (llsaDataflow.getAnalysis().isStoreAlive(liveStoreSet, local)) 246 continue; 247 249 boolean killedBySubsequentStore = llsaDataflow.getAnalysis().killedByStore(liveStoreSet, local); 251 if (killedBySubsequentStore) 252 propertySet.addProperty(DeadLocalStoreProperty.KILLED_BY_SUBSEQUENT_STORE); 253 254 InstructionHandle prev = location.getBasicBlock().getPredecessorOf(location.getHandle()); 257 int prevOpCode = -1; 258 259 if (prev != null 260 && defensiveConstantValueOpcodes.get(prev.getInstruction().getOpcode())) { 261 propertySet.addProperty(DeadLocalStoreProperty.DEFENSIVE_CONSTANT_OPCODE); 262 prevOpCode = prev.getInstruction().getOpcode(); 263 } 264 265 if (prev != null && prev.getInstruction() instanceof GETFIELD) { 266 InstructionHandle prev2 = prev.getPrev(); 267 268 if (prev2 != null 269 && prev2.getInstruction() instanceof ALOAD) 270 propertySet.addProperty(DeadLocalStoreProperty.CACHING_VALUE); 271 } 272 273 274 if (ins instanceof IINC) { 275 277 propertySet.addProperty(DeadLocalStoreProperty.DEAD_INCREMENT); 278 if (localIncrementCount[local] == 1) { 279 propertySet.addProperty(DeadLocalStoreProperty.SINGLE_DEAD_INCREMENT); 280 } 281 282 } else if (ins instanceof ASTORE && prev != null) { 283 285 Instruction prevIns = prev.getInstruction(); 286 if ((prevIns instanceof INVOKESPECIAL && 287 ((INVOKESPECIAL)prevIns).getMethodName(methodGen.getConstantPool()).equals("<init>")) 288 || prevIns instanceof ANEWARRAY 289 || prevIns instanceof NEWARRAY 290 || prevIns instanceof MULTIANEWARRAY) { 291 propertySet.addProperty(DeadLocalStoreProperty.DEAD_OBJECT_STORE); 292 } 293 294 } else if (!killedBySubsequentStore 295 && localStoreCount[local] == 2 && localLoadCount[local] > 0) { 296 298 propertySet.addProperty(DeadLocalStoreProperty.TWO_STORES_MULTIPLE_LOADS); 299 300 } else if (!parameterThatIsDeadAtEntry && localStoreCount[local] == 1) { 301 303 propertySet.addProperty(DeadLocalStoreProperty.SINGLE_STORE); 304 305 } else if (!parameterThatIsDeadAtEntry && localLoadCount[local] == 0) { 306 308 propertySet.addProperty(DeadLocalStoreProperty.NO_LOADS); 309 310 } 311 312 if (parameterThatIsDeadAtEntry) { 313 propertySet.addProperty(DeadLocalStoreProperty.PARAM_DEAD_ON_ENTRY); 314 if (pendingBugReportAboutOverwrittenParameter != null) 315 pendingBugReportAboutOverwrittenParameter.setPriority(Detector.HIGH_PRIORITY); 316 } 317 318 if (localStoreCount[local] > 3) 319 propertySet.addProperty(DeadLocalStoreProperty.MANY_STORES); 320 int priority = propertySet.computePriority(NORMAL_PRIORITY); 321 if (priority <= Detector.EXP_PRIORITY) { 322 323 324 BugInstance bugInstance = new BugInstance(this, storeOfNull ? "DLS_DEAD_LOCAL_STORE_OF_NULL" : "DLS_DEAD_LOCAL_STORE", priority) 326 .addClassAndMethod(methodGen, javaClass.getSourceFileName()) 327 .add(lvAnnotation); 328 329 330 331 if (FindBugsAnalysisFeatures.isRelaxedMode()) { 333 WarningPropertyUtil.addPropertiesForLocation( 335 propertySet, 336 classContext, 337 method, 338 location); 339 340 propertySet.decorateBugInstance(bugInstance); 342 } 343 SourceLineAnnotation sourceLineAnnotation = 344 SourceLineAnnotation.fromVisitedInstruction(classContext, methodGen, javaClass.getSourceFileName(), 345 location.getHandle()); 346 347 348 if (DEBUG) { 349 System.out.println( 350 javaClass.getSourceFileName() + " : " + 351 methodGen.getName()); 352 System.out.println("priority: " + priority); 353 System.out.println("Reporting " + bugInstance); 354 System.out.println(propertySet); 355 } 356 accumulator.accumulateBug(bugInstance, sourceLineAnnotation); 357 } 358 } finally { 359 if (pendingBugReportAboutOverwrittenParameter != null) 360 bugReporter.reportBug(pendingBugReportAboutOverwrittenParameter); 361 } 362 } 363 accumulator.reportAccumulatedBugs(); 364 } 365 366 367 368 369 378 private void countLocalStoresLoadsAndIncrements(int[] localStoreCount, int[] localLoadCount, int[] localIncrementCount, CFG cfg) { 379 for (Iterator <Location> i = cfg.locationIterator(); i.hasNext(); ) { 380 Location location = i.next(); 381 382 if (location.getBasicBlock().isExceptionHandler()) 383 continue; 384 385 boolean isStore = isStore(location); 386 boolean isLoad = isLoad(location); 387 if (!isStore && !isLoad) 388 continue; 389 390 IndexedInstruction ins = (IndexedInstruction) location.getHandle().getInstruction(); 391 int local = ins.getIndex(); 392 if (ins instanceof IINC) { 393 localStoreCount[local]++; 394 localLoadCount[local]++; 395 localIncrementCount[local]++; 396 } else if (isStore) 397 localStoreCount[local]++; 398 else 399 localLoadCount[local]++; 400 } 401 } 402 403 411 private void checkLocalVariableName(LocalVariableTable lvt, int local, int pc, 412 WarningPropertySet propertySet) { 413 if (lvt != null) { 414 LocalVariable lv = lvt.getLocalVariable(local, pc); 415 if (lv != null) { 416 String localName = lv.getName(); 417 propertySet.setProperty(DeadLocalStoreProperty.LOCAL_NAME, localName); 418 } 419 } 420 421 } 422 423 429 private boolean isStore(Location location) { 430 Instruction ins = location.getHandle().getInstruction(); 431 return (ins instanceof StoreInstruction) || (ins instanceof IINC); 432 } 433 434 440 private boolean isLoad(Location location) { 441 Instruction ins = location.getHandle().getInstruction(); 442 return (ins instanceof LoadInstruction) || (ins instanceof IINC); 443 } 444 445 public void report() { 446 } 447 } 448 449 | Popular Tags |