1 17 package org.apache.bcel.verifier.structurals; 18 19 20 import java.io.PrintWriter ; 21 import java.io.StringWriter ; 22 import java.util.ArrayList ; 23 import java.util.List ; 24 import java.util.Random ; 25 import java.util.Vector ; 26 import org.apache.bcel.Constants; 27 import org.apache.bcel.Repository; 28 import org.apache.bcel.classfile.JavaClass; 29 import org.apache.bcel.classfile.Method; 30 import org.apache.bcel.generic.ConstantPoolGen; 31 import org.apache.bcel.generic.InstructionHandle; 32 import org.apache.bcel.generic.JsrInstruction; 33 import org.apache.bcel.generic.MethodGen; 34 import org.apache.bcel.generic.ObjectType; 35 import org.apache.bcel.generic.RET; 36 import org.apache.bcel.generic.ReturnInstruction; 37 import org.apache.bcel.generic.ReturnaddressType; 38 import org.apache.bcel.generic.Type; 39 import org.apache.bcel.verifier.PassVerifier; 40 import org.apache.bcel.verifier.VerificationResult; 41 import org.apache.bcel.verifier.Verifier; 42 import org.apache.bcel.verifier.exc.AssertionViolatedException; 43 import org.apache.bcel.verifier.exc.VerifierConstraintViolatedException; 44 45 56 57 public final class Pass3bVerifier extends PassVerifier{ 58 61 62 75 private static final class InstructionContextQueue{ 76 private List ics = new Vector (); private List ecs = new Vector (); public void add(InstructionContext ic, ArrayList executionChain){ 79 ics.add(ic); 80 ecs.add(executionChain); 81 } 82 public boolean isEmpty(){ 83 return ics.isEmpty(); 84 } 85 public void remove(){ 86 this.remove(0); 87 } 88 public void remove(int i){ 89 ics.remove(i); 90 ecs.remove(i); 91 } 92 public InstructionContext getIC(int i){ 93 return (InstructionContext) ics.get(i); 94 } 95 public ArrayList getEC(int i){ 96 return (ArrayList ) ecs.get(i); 97 } 98 public int size(){ 99 return ics.size(); 100 } 101 } 103 104 private static final boolean DEBUG = true; 105 106 107 private Verifier myOwner; 108 109 110 private int method_no; 111 112 117 public Pass3bVerifier(Verifier owner, int method_no){ 118 myOwner = owner; 119 this.method_no = method_no; 120 } 121 122 129 private void circulationPump(ControlFlowGraph cfg, InstructionContext start, Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev){ 130 final Random random = new Random (); 131 InstructionContextQueue icq = new InstructionContextQueue(); 132 133 start.execute(vanillaFrame, new ArrayList (), icv, ev); icq.add(start, new ArrayList ()); 136 137 while (!icq.isEmpty()){ 139 InstructionContext u; 140 ArrayList ec; 141 if (!DEBUG){ 142 int r = random.nextInt(icq.size()); 143 u = icq.getIC(r); 144 ec = icq.getEC(r); 145 icq.remove(r); 146 } 147 else{ 148 u = icq.getIC(0); 149 ec = icq.getEC(0); 150 icq.remove(0); 151 } 152 153 ArrayList oldchain = (ArrayList ) (ec.clone()); 154 ArrayList newchain = (ArrayList ) (ec.clone()); 155 newchain.add(u); 156 157 if ((u.getInstruction().getInstruction()) instanceof RET){ 158 RET ret = (RET) (u.getInstruction().getInstruction()); 162 ReturnaddressType t = (ReturnaddressType) u.getOutFrame(oldchain).getLocals().get(ret.getIndex()); 163 InstructionContext theSuccessor = cfg.contextOf(t.getTarget()); 164 165 InstructionContext lastJSR = null; 167 int skip_jsr = 0; 168 for (int ss=oldchain.size()-1; ss >= 0; ss--){ 169 if (skip_jsr < 0){ 170 throw new AssertionViolatedException("More RET than JSR in execution chain?!"); 171 } 172 if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction){ 174 if (skip_jsr == 0){ 175 lastJSR = (InstructionContext) oldchain.get(ss); 176 break; 177 } 178 else{ 179 skip_jsr--; 180 } 181 } 182 if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof RET){ 183 skip_jsr++; 184 } 185 } 186 if (lastJSR == null){ 187 throw new AssertionViolatedException("RET without a JSR before in ExecutionChain?! EC: '"+oldchain+"'."); 188 } 189 JsrInstruction jsr = (JsrInstruction) (lastJSR.getInstruction().getInstruction()); 190 if ( theSuccessor != (cfg.contextOf(jsr.physicalSuccessor())) ){ 191 throw new AssertionViolatedException("RET '"+u.getInstruction()+"' info inconsistent: jump back to '"+theSuccessor+"' or '"+cfg.contextOf(jsr.physicalSuccessor())+"'?"); 192 } 193 194 if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)){ 195 icq.add(theSuccessor, (ArrayList ) newchain.clone()); 196 } 197 } 198 else{ 200 InstructionContext[] succs = u.getSuccessors(); 202 for (int s=0; s<succs.length; s++){ 203 InstructionContext v = succs[s]; 204 if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)){ 205 icq.add(v, (ArrayList ) newchain.clone()); 206 } 207 } 208 } 210 ExceptionHandler[] exc_hds = u.getExceptionHandlers(); 213 for (int s=0; s<exc_hds.length; s++){ 214 InstructionContext v = cfg.contextOf(exc_hds[s].getHandlerStart()); 215 if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack (u.getOutFrame(oldchain).getStack().maxStack(), (exc_hds[s].getExceptionType()==null? Type.THROWABLE : exc_hds[s].getExceptionType())) ), new ArrayList (), icv, ev)){ 226 icq.add(v, new ArrayList ()); 227 } 228 } 229 230 } 232 InstructionHandle ih = start.getInstruction(); 233 do{ 234 if ((ih.getInstruction() instanceof ReturnInstruction) && (!(cfg.isDead(ih)))) { 235 InstructionContext ic = cfg.contextOf(ih); 236 Frame f = ic.getOutFrame(new ArrayList ()); LocalVariables lvs = f.getLocals(); 238 for (int i=0; i<lvs.maxLocals(); i++){ 239 if (lvs.get(i) instanceof UninitializedObjectType){ 240 this.addMessage("Warning: ReturnInstruction '"+ic+"' may leave method with an uninitialized object in the local variables array '"+lvs+"'."); 241 } 242 } 243 OperandStack os = f.getStack(); 244 for (int i=0; i<os.size(); i++){ 245 if (os.peek(i) instanceof UninitializedObjectType){ 246 this.addMessage("Warning: ReturnInstruction '"+ic+"' may leave method with an uninitialized object on the operand stack '"+os+"'."); 247 } 248 } 249 } 250 }while ((ih = ih.getNext()) != null); 251 252 } 253 254 264 public VerificationResult do_verify(){ 265 if (! myOwner.doPass3a(method_no).equals(VerificationResult.VR_OK)){ 266 return VerificationResult.VR_NOTYET; 267 } 268 269 JavaClass jc; 272 try { 273 jc = Repository.lookupClass(myOwner.getClassName()); 274 } catch (ClassNotFoundException e) { 275 throw new AssertionViolatedException("Missing class: " + e.toString()); 277 } 278 279 ConstantPoolGen constantPoolGen = new ConstantPoolGen(jc.getConstantPool()); 280 InstConstraintVisitor icv = new InstConstraintVisitor(); 282 icv.setConstantPoolGen(constantPoolGen); 283 284 ExecutionVisitor ev = new ExecutionVisitor(); 285 ev.setConstantPoolGen(constantPoolGen); 286 287 Method[] methods = jc.getMethods(); 289 try{ 290 291 MethodGen mg = new MethodGen(methods[method_no], myOwner.getClassName(), constantPoolGen); 292 293 icv.setMethodGen(mg); 294 295 if (! (mg.isAbstract() || mg.isNative()) ){ 298 ControlFlowGraph cfg = new ControlFlowGraph(mg); 299 300 Frame f = new Frame(mg.getMaxLocals(),mg.getMaxStack()); 302 if ( !mg.isStatic() ){ 303 if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)){ 304 Frame._this = new UninitializedObjectType(new ObjectType(jc.getClassName())); 305 f.getLocals().set(0, Frame._this); 306 } 307 else{ 308 Frame._this = null; 309 f.getLocals().set(0, new ObjectType(jc.getClassName())); 310 } 311 } 312 Type[] argtypes = mg.getArgumentTypes(); 313 int twoslotoffset = 0; 314 for (int j=0; j<argtypes.length; j++){ 315 if (argtypes[j] == Type.SHORT || argtypes[j] == Type.BYTE || argtypes[j] == Type.CHAR || argtypes[j] == Type.BOOLEAN){ 316 argtypes[j] = Type.INT; 317 } 318 f.getLocals().set(twoslotoffset + j + (mg.isStatic()?0:1), argtypes[j]); 319 if (argtypes[j].getSize() == 2){ 320 twoslotoffset++; 321 f.getLocals().set(twoslotoffset + j + (mg.isStatic()?0:1), Type.UNKNOWN); 322 } 323 } 324 circulationPump(cfg, cfg.contextOf(mg.getInstructionList().getStart()), f, icv, ev); 325 } 326 } 327 catch (VerifierConstraintViolatedException ce){ 328 ce.extendMessage("Constraint violated in method '"+methods[method_no]+"':\n",""); 329 return new VerificationResult(VerificationResult.VERIFIED_REJECTED, ce.getMessage()); 330 } 331 catch (RuntimeException re){ 332 334 StringWriter sw = new StringWriter (); 335 PrintWriter pw = new PrintWriter (sw); 336 re.printStackTrace(pw); 337 338 throw new AssertionViolatedException("Some RuntimeException occured while verify()ing class '"+jc.getClassName()+"', method '"+methods[method_no]+"'. Original RuntimeException's stack trace:\n---\n"+sw+"---\n"); 339 } 340 return VerificationResult.VR_OK; 341 } 342 343 344 public int getMethodNo(){ 345 return method_no; 346 } 347 } 348 | Popular Tags |