1 19 20 package edu.umd.cs.findbugs.detect; 21 22 23 import edu.umd.cs.findbugs.*; 24 import edu.umd.cs.findbugs.ba.*; 25 import edu.umd.cs.findbugs.ba.bcp.*; 26 import java.util.*; 27 import org.apache.bcel.Constants; 28 import org.apache.bcel.classfile.*; 29 import org.apache.bcel.generic.*; 30 31 38 39 public final class LazyInit extends ByteCodePatternDetector implements StatelessDetector { 40 private BugReporter bugReporter; 41 42 private static final boolean DEBUG = SystemProperties.getBoolean("lazyinit.debug"); 43 44 47 private static ByteCodePattern pattern = new ByteCodePattern(); 48 49 static { 50 pattern 51 .add(new Load("f", "val").label("start")) 52 .add(new IfNull("val")) 53 .add(new Wild(1, 1).label("createObject")) 54 .add(new Store("f", pattern.dummyVariable()).label("end").dominatedBy("createObject")); 55 } 56 57 public LazyInit(BugReporter bugReporter) { 58 this.bugReporter = bugReporter; 59 } 60 @Override 61 public Object clone() { 62 try { 63 return super.clone(); 64 } catch (CloneNotSupportedException e) { 65 throw new AssertionError (e); 66 } 67 } 68 @Override 69 public BugReporter getBugReporter() { 70 return bugReporter; 71 } 72 73 74 75 @Override 76 public ByteCodePattern getPattern() { 77 return pattern; 78 } 79 80 @Override 81 public boolean prescreen(Method method, ClassContext classContext) { 82 BitSet bytecodeSet = classContext.getBytecodeSet(method); 83 if (bytecodeSet == null) return false; 84 if (!(bytecodeSet.get(Constants.GETSTATIC) && bytecodeSet.get(Constants.PUTSTATIC)) && 86 !(bytecodeSet.get(Constants.GETFIELD) && bytecodeSet.get(Constants.PUTFIELD))) 87 return false; 88 89 if (method.isSynchronized()) 92 return false; 93 94 return true; 95 } 96 97 @Override 98 public void reportMatch(ClassContext classContext, Method method, ByteCodePatternMatch match) 99 throws CFGBuilderException, DataflowAnalysisException { 100 JavaClass javaClass = classContext.getJavaClass(); 101 MethodGen methodGen = classContext.getMethodGen(method); 102 CFG cfg = classContext.getCFG(method); 103 104 try { 105 BindingSet bindingSet = match.getBindingSet(); 107 Binding binding = bindingSet.lookup("f"); 108 109 FieldVariable field = (FieldVariable) binding.getVariable(); 112 XField xfield = 113 Hierarchy.findXField(field.getClassName(), field.getFieldName(), field.getFieldSig()); 114 if (xfield == null || (xfield.getAccessFlags() & Constants.ACC_VOLATILE) != 0) 115 return; 116 117 if (!xfield.isStatic()) 119 return; 120 121 if (xfield.getName().startsWith("class$") || xfield.getName().startsWith("array$")) { 123 if (DEBUG) System.out.println("Ignoring field " + xfield.getName()); 124 return; 125 } 126 127 if (!xfield.getSignature().startsWith("[")) { 129 if (DEBUG) System.out.println("Ignoring non-reference field " + xfield.getName()); 130 return; 131 } 132 133 135 PatternElementMatch createBegin = match.getFirstLabeledMatch("createObject"); 138 PatternElementMatch store = match.getFirstLabeledMatch("end"); 139 140 DominatorsAnalysis domAnalysis = 150 classContext.getNonExceptionDominatorsAnalysis(method); 151 PostDominatorsAnalysis postDomAnalysis = 152 classContext.getNonExceptionPostDominatorsAnalysis(method); 153 BitSet extent = domAnalysis.getAllDominatedBy(createBegin.getBasicBlock()); 154 extent.and(postDomAnalysis.getAllDominatedBy(store.getBasicBlock())); 155 if (DEBUG) System.out.println("Object creation extent: " + extent); 157 158 LockDataflow lockDataflow = classContext.getLockDataflow(method); 166 LockSet lockSet = null; 167 boolean sawNEW = false, sawINVOKE = false; 168 for (BasicBlock block : cfg.getBlocks(extent)) { 169 for (Iterator<InstructionHandle> j = block.instructionIterator(); j.hasNext();) { 170 InstructionHandle handle = j.next(); 171 172 Location location = new Location(handle, block); 173 174 Instruction ins = handle.getInstruction(); 177 if (ins instanceof NEW) 178 sawNEW = true; 179 else if (ins instanceof InvokeInstruction) 180 sawINVOKE = true; 181 182 LockSet insLockSet = lockDataflow.getFactAtLocation(location); 184 if (lockSet == null) { 185 lockSet = new LockSet(); 186 lockSet.copyFrom(insLockSet); 187 } else 188 lockSet.intersectWith(insLockSet); 189 } 190 } 191 if (!(sawNEW || sawINVOKE)) 192 return; 193 if (lockSet == null) throw new IllegalStateException (); 194 if (!lockSet.isEmpty()) 195 return; 196 197 int priority = LOW_PRIORITY; 203 boolean isDefaultAccess = 204 (method.getAccessFlags() & (Constants.ACC_PUBLIC | Constants.ACC_PRIVATE | Constants.ACC_PROTECTED)) == 0; 205 if (method.isPublic()) 206 priority = NORMAL_PRIORITY; 207 else if (method.isProtected() || isDefaultAccess) 208 priority = NORMAL_PRIORITY; 209 210 InstructionHandle start = match.getLabeledInstruction("start"); 212 InstructionHandle end = match.getLabeledInstruction("end"); 213 String sourceFile = javaClass.getSourceFileName(); 214 bugReporter.reportBug(new BugInstance(this, "LI_LAZY_INIT_STATIC", priority) 215 .addClassAndMethod(methodGen, sourceFile) 216 .addField(xfield).describe("FIELD_ON") 217 .addSourceLine(classContext, methodGen, sourceFile, start, end)); 218 } catch (ClassNotFoundException e) { 219 bugReporter.reportMissingClass(e); 220 } 221 } 222 223 } 224 225 | Popular Tags |