static void nullAspectjBCELAdapt(final byte[] b) throws IOException { org.aspectj.apache.bcel.classfile.JavaClass jc = new org.aspectj.apache.bcel.classfile.ClassParser(new ByteArrayInputStream(b), "class-name") .parse(); org.aspectj.apache.bcel.generic.ClassGen cg = new org.aspectj.apache.bcel.generic.ClassGen(jc); org.aspectj.apache.bcel.generic.ConstantPoolGen cp = cg.getConstantPool(); org.aspectj.apache.bcel.classfile.Method[] ms = cg.getMethods(); for (int k = 0; k < ms.length; ++k) { org.aspectj.apache.bcel.generic.MethodGen mg = new org.aspectj.apache.bcel.generic.MethodGen(ms[k], cg.getClassName(), cp); boolean lv = ms[k].getLocalVariableTable() == null; boolean ln = ms[k].getLineNumberTable() == null; if (lv) { mg.removeLocalVariables(); } if (ln) { mg.removeLineNumbers(); } mg.stripAttributes(skipDebug); org.aspectj.apache.bcel.generic.InstructionList il = mg.getInstructionList(); if (il != null) { org.aspectj.apache.bcel.generic.InstructionHandle ih = il.getStart(); while (ih != null) { ih = ih.getNext(); } if (compute) { mg.setMaxStack(); mg.setMaxLocals(); } if (computeFrames) { org.aspectj.apache.bcel.verifier.structurals.ModifiedPass3bVerifier verif = new org.aspectj.apache.bcel.verifier.structurals.ModifiedPass3bVerifier(jc, k); verif.do_verify(); } } cg.replaceMethod(ms[k], mg.getMethod()); } cg.getJavaClass().getBytes(); }
/** * Whenever the outgoing frame situation of an InstructionContext changes, all its successors are * put [back] into the queue [as if they were unvisited]. The proof of termination is about the * existence of a fix point of frame merging. */ private void circulationPump( ControlFlowGraph cfg, InstructionContext start, Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev) { final Random random = new Random(); InstructionContextQueue icq = new InstructionContextQueue(); start.execute( vanillaFrame, new ArrayList(), icv, ev); // new ArrayList() <=> no Instruction was executed before // => Top-Level routine (no jsr call before) icq.add(start, new ArrayList()); // LOOP! while (!icq.isEmpty()) { InstructionContext u; ArrayList ec; if (!DEBUG) { int r = random.nextInt(icq.size()); u = icq.getIC(r); ec = icq.getEC(r); icq.remove(r); } else { u = icq.getIC(0); ec = icq.getEC(0); icq.remove(0); } ArrayList oldchain = (ArrayList) (ec.clone()); ArrayList newchain = (ArrayList) (ec.clone()); newchain.add(u); if ((u.getInstruction().getInstruction()) instanceof RET) { // System.err.println(u); // We can only follow _one_ successor, the one after the // JSR that was recently executed. RET ret = (RET) (u.getInstruction().getInstruction()); ReturnaddressType t = (ReturnaddressType) u.getOutFrame(oldchain).getLocals().get(ret.getIndex()); InstructionContext theSuccessor = cfg.contextOf(t.getTarget()); // Sanity check InstructionContext lastJSR = null; int skip_jsr = 0; for (int ss = oldchain.size() - 1; ss >= 0; ss--) { if (skip_jsr < 0) { throw new AssertionViolatedException("More RET than JSR in execution chain?!"); } // System.err.println("+"+oldchain.get(ss)); if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction) { if (skip_jsr == 0) { lastJSR = (InstructionContext) oldchain.get(ss); break; } else { skip_jsr--; } } if (((InstructionContext) oldchain.get(ss)).getInstruction().getInstruction() instanceof RET) { skip_jsr++; } } if (lastJSR == null) { throw new AssertionViolatedException( "RET without a JSR before in ExecutionChain?! EC: '" + oldchain + "'."); } JsrInstruction jsr = (JsrInstruction) (lastJSR.getInstruction().getInstruction()); if (theSuccessor != (cfg.contextOf(jsr.physicalSuccessor()))) { throw new AssertionViolatedException( "RET '" + u.getInstruction() + "' info inconsistent: jump back to '" + theSuccessor + "' or '" + cfg.contextOf(jsr.physicalSuccessor()) + "'?"); } if (theSuccessor.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { icq.add(theSuccessor, (ArrayList) newchain.clone()); } } else { // "not a ret" // Normal successors. Add them to the queue of successors. InstructionContext[] succs = u.getSuccessors(); for (int s = 0; s < succs.length; s++) { InstructionContext v = succs[s]; if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)) { icq.add(v, (ArrayList) newchain.clone()); } } } // end "not a ret" // Exception Handlers. Add them to the queue of successors. // [subroutines are never protected; mandated by JustIce] ExceptionHandler[] exc_hds = u.getExceptionHandlers(); for (int s = 0; s < exc_hds.length; s++) { InstructionContext v = cfg.contextOf(exc_hds[s].getHandlerStart()); // TODO: the "oldchain" and "newchain" is used to determine the subroutine // we're in (by searching for the last JSR) by the InstructionContext // implementation. Therefore, we should not use this chain mechanism // when dealing with exception handlers. // Example: a JSR with an exception handler as its successor does not // mean we're in a subroutine if we go to the exception handler. // We should address this problem later; by now we simply "cut" the chain // by using an empty chain for the exception handlers. // if (v.execute(new Frame(u.getOutFrame(oldchain).getLocals(), new OperandStack // (u.getOutFrame().getStack().maxStack(), (exc_hds[s].getExceptionType()==null? // Type.THROWABLE : exc_hds[s].getExceptionType())) ), newchain), icv, ev){ // icq.add(v, (ArrayList) newchain.clone()); 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)) { icq.add(v, new ArrayList()); } } } // while (!icq.isEmpty()) END InstructionHandle ih = start.getInstruction(); do { if ((ih.getInstruction() instanceof ReturnInstruction) && (!(cfg.isDead(ih)))) { InstructionContext ic = cfg.contextOf(ih); Frame f = ic.getOutFrame( new ArrayList()); // TODO: This is buggy, we check only the top-level return // instructions this way. Maybe some maniac returns from a method // when in a subroutine? LocalVariables lvs = f.getLocals(); for (int i = 0; i < lvs.maxLocals(); i++) { if (lvs.get(i) instanceof UninitializedObjectType) { this.addMessage( "Warning: ReturnInstruction '" + ic + "' may leave method with an uninitialized object in the local variables array '" + lvs + "'."); } } OperandStack os = f.getStack(); for (int i = 0; i < os.size(); i++) { if (os.peek(i) instanceof UninitializedObjectType) { this.addMessage( "Warning: ReturnInstruction '" + ic + "' may leave method with an uninitialized object on the operand stack '" + os + "'."); } } } } while ((ih = ih.getNext()) != null); }