1 19 20 package edu.umd.cs.findbugs.ba.obl; 21 22 import java.util.Iterator ; 23 import java.util.Map ; 24 25 import org.apache.bcel.Constants; 26 import org.apache.bcel.generic.ConstantPoolGen; 27 import org.apache.bcel.generic.Instruction; 28 import org.apache.bcel.generic.InstructionHandle; 29 import org.apache.bcel.generic.InvokeInstruction; 30 import org.apache.bcel.generic.MethodGen; 31 import org.apache.bcel.generic.ObjectType; 32 import org.apache.bcel.generic.Type; 33 34 import edu.umd.cs.findbugs.SystemProperties; 35 import edu.umd.cs.findbugs.annotations.CheckForNull; 36 import edu.umd.cs.findbugs.ba.AnalysisContext; 37 import edu.umd.cs.findbugs.ba.BasicBlock; 38 import edu.umd.cs.findbugs.ba.DataflowAnalysisException; 39 import edu.umd.cs.findbugs.ba.DepthFirstSearch; 40 import edu.umd.cs.findbugs.ba.Edge; 41 import edu.umd.cs.findbugs.ba.EdgeTypes; 42 import edu.umd.cs.findbugs.ba.ForwardDataflowAnalysis; 43 import edu.umd.cs.findbugs.ba.Location; 44 import edu.umd.cs.findbugs.ba.RepositoryLookupFailureCallback; 45 import edu.umd.cs.findbugs.ba.type.TypeDataflow; 46 import edu.umd.cs.findbugs.ba.type.TypeFrame; 47 48 59 public class ObligationAnalysis 60 extends ForwardDataflowAnalysis<StateSet> { 61 62 private static final boolean DEBUG = SystemProperties.getBoolean("oa.debug"); 63 64 private TypeDataflow typeDataflow; 65 private MethodGen methodGen; 66 private ObligationFactory factory; 67 private PolicyDatabase database; 68 private RepositoryLookupFailureCallback lookupFailureCallback; 69 70 81 public ObligationAnalysis( 82 DepthFirstSearch dfs, 83 TypeDataflow typeDataflow, 84 MethodGen methodGen, 85 ObligationFactory factory, 86 PolicyDatabase database, 87 RepositoryLookupFailureCallback lookupFailureCallback) { 88 super(dfs); 89 this.typeDataflow = typeDataflow; 90 this.methodGen = methodGen; 91 this.factory = factory; 92 this.database = database; 93 this.lookupFailureCallback = lookupFailureCallback; 94 } 95 96 public StateSet createFact() { 97 return new StateSet(factory); 98 } 99 100 @Override 101 public boolean isFactValid(StateSet fact) { 102 return fact.isValid(); 103 } 104 105 @Override 106 public void transferInstruction(InstructionHandle handle, BasicBlock basicBlock, StateSet fact) 107 throws DataflowAnalysisException { 108 109 Obligation obligation; 110 111 if ((obligation = addsObligation(handle)) != null) { 112 if (DEBUG) { System.out.println("Adding obligation " + obligation.toString()); } 114 fact.addObligation(obligation); 115 } else if ((obligation = deletesObligation(handle)) != null) { 116 if (DEBUG) { System.out.println("Deleting obligation " + obligation.toString()); } 118 deleteObligation(fact, obligation, handle); 119 } 120 121 } 122 123 126 @Override 127 public void transfer(BasicBlock basicBlock, @CheckForNull InstructionHandle end, StateSet start, StateSet result) throws DataflowAnalysisException { 128 super.transfer(basicBlock, end, start, result); 129 endTransfer(basicBlock, end, result); 130 } 131 132 public void endTransfer(BasicBlock basicBlock, @CheckForNull InstructionHandle end, StateSet result) 133 throws DataflowAnalysisException { 134 for (Iterator <State> i = result.stateIterator(); i.hasNext(); ) { 136 State state = i.next(); 137 state.getPath().append(basicBlock.getId()); 138 } 139 } 140 141 private Obligation addsObligation(InstructionHandle handle) { 142 return addsOrDeletesObligation(handle, PolicyDatabase.ADD); 143 } 144 145 private Obligation deletesObligation(InstructionHandle handle) { 146 return addsOrDeletesObligation(handle, PolicyDatabase.DEL); 147 } 148 149 private Obligation addsOrDeletesObligation(InstructionHandle handle, int action) { 150 Instruction ins = handle.getInstruction(); 151 152 if (!(ins instanceof InvokeInstruction)) 153 return null; 154 155 InvokeInstruction inv = (InvokeInstruction) ins; 156 157 ConstantPoolGen cpg = methodGen.getConstantPool(); 158 159 String className = inv.getClassName(cpg); 160 162 String methodName = inv.getName(cpg); 163 String signature = inv.getSignature(cpg); 164 boolean isStatic = inv.getOpcode() == Constants.INVOKESTATIC; 165 166 if (DEBUG) { 167 System.out.println("Checking instruction: " + handle); 168 System.out.println(" class =" + className); 169 System.out.println(" method =" + methodName); 170 System.out.println(" signature=" + signature); 171 } 172 173 try { 174 return database.lookup( 175 className, methodName, signature, isStatic, action); 176 } catch (ClassNotFoundException e) { 177 lookupFailureCallback.reportMissingClass(e); 178 return null; 179 } 180 181 } 182 183 192 private void deleteObligation(StateSet fact, Obligation obligation, InstructionHandle handle) 193 throws DataflowAnalysisException { 194 try { 195 fact.deleteObligation(obligation); 196 } catch (NonexistentObligationException e) { 197 throw new DataflowAnalysisException( 198 "Removing nonexistent obligation of type " + obligation.toString(), 199 methodGen, handle, e); 200 } 201 } 202 203 206 public void copy(StateSet src, StateSet dest) { 207 dest.copyFrom(src); 208 } 209 210 213 public void initEntryFact(StateSet fact) throws DataflowAnalysisException { 214 fact.initEntryFact(factory); 215 } 216 217 220 public void initResultFact(StateSet fact) { 221 fact.setTop(); 222 } 223 224 227 public void makeFactTop(StateSet fact) { 228 fact.setTop(); 229 } 230 public boolean isTop(StateSet fact) { 231 return fact.isTop(); 232 } 233 234 237 public boolean same(StateSet a, StateSet b) { 238 return a.equals(b); 239 } 240 241 244 public void meetInto(StateSet fact, Edge edge, StateSet result) 245 throws DataflowAnalysisException { 246 247 if (edge.isExceptionEdge() && fact.isValid()) { 251 BasicBlock sourceBlock = edge.getSource(); 252 InstructionHandle handle = sourceBlock.getExceptionThrower(); 253 Obligation obligation; 254 if ((obligation = deletesObligation(handle)) != null) { 255 fact = fact.duplicate(); 256 deleteObligation(fact, obligation, handle); 257 } 258 } 259 260 if (isPossibleIfComparison(edge)) { 265 Obligation obligation; 266 if ((obligation = comparesObligationTypeToNull(edge)) != null) { 267 fact = fact.duplicate(); 268 if (DEBUG) { 269 System.out.println("Deleting " + obligation.toString() + 270 " on edge from comparision " + edge.getSource().getLastInstruction()); 271 } 272 deleteObligation(fact, obligation, edge.getSource().getLastInstruction()); 273 } 274 } 275 276 final StateSet inputFact = fact; 277 278 if (inputFact.isTop() || result.isBottom()) { 280 } else if (inputFact.isBottom() || result.isTop()) { 282 copy(inputFact, result); 283 } else { 284 291 final Map <ObligationSet, State> updatedStateMap = result.createEmptyMap(); 294 295 for (Iterator <State> i = inputFact.stateIterator(); i.hasNext(); ) { 299 State otherState = i.next(); 300 if (result.getStateWithObligationSet(otherState.getObligationSet()) == null) { 301 State dup = otherState.duplicate(); 304 updatedStateMap.put(dup.getObligationSet(), dup); 305 } 306 } 307 308 StateSet.StateCallback callback = new StateSet.StateCallback() { 312 public void apply(State state) throws NonexistentObligationException { 313 State matchingState = inputFact.getStateWithObligationSet(state.getObligationSet()); 315 if (matchingState != null) { 316 if (state.getPath().getLength() > matchingState.getPath().getLength()) { 318 state.getPath().copyFrom(matchingState.getPath()); 319 } 320 } 321 updatedStateMap.put(state.getObligationSet(), state); 322 } 323 }; 324 325 try { 326 result.applyToAllStatesAndUpdateMap(callback, updatedStateMap); 327 } catch (NonexistentObligationException e) { 328 throw new DataflowAnalysisException("This shouldn't happen", e); 331 } 332 } 333 } 334 335 private boolean isPossibleIfComparison(Edge edge) { 336 return edge.getType() == EdgeTypes.IFCMP_EDGE 337 || edge.getType() == EdgeTypes.FALL_THROUGH_EDGE; 338 } 339 340 private Obligation comparesObligationTypeToNull(Edge edge) 341 throws DataflowAnalysisException { 342 BasicBlock sourceBlock = edge.getSource(); 343 InstructionHandle last = sourceBlock.getLastInstruction(); 344 if (last == null) 345 return null; 346 347 Type type; 348 349 short opcode = last.getInstruction().getOpcode(); 350 switch (opcode) { 351 case Constants.IFNULL: 352 case Constants.IFNONNULL: 353 if ( (edge.getType() == EdgeTypes.IFCMP_EDGE && opcode == Constants.IFNONNULL) 354 || (edge.getType() == EdgeTypes.FALL_THROUGH_EDGE && opcode == Constants.IFNULL)) 355 return null; 356 357 Location location = new Location(last, sourceBlock); 358 TypeFrame typeFrame = typeDataflow.getFactAtLocation(location); 359 type = typeFrame.getTopValue(); 360 break; 361 362 370 371 default: 372 return null; 373 } 374 375 if (!(type instanceof ObjectType)) 376 return null; 377 378 try { 379 return factory.getObligationByType((ObjectType) type); 380 } catch (ClassNotFoundException e) { 381 AnalysisContext.reportMissingClass(e); 382 throw new DataflowAnalysisException( 383 "Subtype query failed during ObligationAnalysis", e); 384 } 385 386 } 387 } 388 389 | Popular Tags |