| Code with Finding: |
class Pass3bVerifier {
/**
* 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(MethodGen m,ControlFlowGraph cfg, InstructionContext start,
Frame vanillaFrame, InstConstraintVisitor icv, ExecutionVisitor ev){
final Random random = new Random();
InstructionContextQueue icq = new InstructionContextQueue();
start.execute(vanillaFrame, new ArrayList<InstructionContext>(), icv, ev);
// new ArrayList() <=> no Instruction was executed before
// => Top-Level routine (no jsr call before)
icq.add(start, new ArrayList<InstructionContext>());
// LOOP!
while (!icq.isEmpty()){
InstructionContext u;
ArrayList<InstructionContext> 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);
}
@SuppressWarnings("unchecked") // ec is of type ArrayList<InstructionContext>
ArrayList<InstructionContext> oldchain = (ArrayList<InstructionContext>) (ec.clone());
@SuppressWarnings("unchecked") // ec is of type ArrayList<InstructionContext>
ArrayList<InstructionContext> newchain = (ArrayList<InstructionContext>) (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 ((oldchain.get(ss)).getInstruction().getInstruction() instanceof JsrInstruction){
if (skip_jsr == 0){
lastJSR = oldchain.get(ss);
break;
}
skip_jsr--;
}
if ((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)){
@SuppressWarnings("unchecked") // newchain is already of type ArrayList<InstructionContext>
ArrayList<InstructionContext> newchainClone = (ArrayList<InstructionContext>) newchain.clone();
icq.add(theSuccessor, newchainClone);
}
}
else{// "not a ret"
// Normal successors. Add them to the queue of successors.
InstructionContext[] succs = u.getSuccessors();
for (InstructionContext v : succs) {
if (v.execute(u.getOutFrame(oldchain), newchain, icv, ev)){
@SuppressWarnings("unchecked") // newchain is already of type ArrayList<InstructionContext>
ArrayList<InstructionContext> newchainClone = (ArrayList<InstructionContext>) newchain.clone();
icq.add(v, newchainClone);
}
}
}// 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 (ExceptionHandler exc_hd : exc_hds) {
InstructionContext v = cfg.contextOf(exc_hd.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_hd.getExceptionType()==null? Type.THROWABLE : exc_hd.getExceptionType())),
new ArrayList<InstructionContext>(), icv, ev)){
icq.add(v, new ArrayList<InstructionContext>());
}
}
}// while (!icq.isEmpty()) END
InstructionHandle ih = start.getInstruction();
do{
if ((ih.getInstruction() instanceof ReturnInstruction) && (!(cfg.isDead(ih)))) {
InstructionContext ic = cfg.contextOf(ih);
// 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?
Frame f = ic.getOutFrame(new ArrayList<InstructionContext>());
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+"'.");
}
}
//see JVM $4.8.2
Type returnedType = null;
OperandStack inStack = ic.getInFrame().getStack();
if (inStack.size() >= 1) {
returnedType = inStack.peek();
} else {
returnedType = Type.VOID;
}
if (returnedType != null) {
if (returnedType instanceof ReferenceType) {
try {
if (!((ReferenceType) returnedType).isCastableTo(m.getReturnType())) {
invalidReturnTypeError(returnedType, m);
}
} catch (ClassNotFoundException e) {
// Don't know what do do now, so raise RuntimeException
throw new RuntimeException(e);
}
} else if (!returnedType.equals(m.getReturnType().normalizeForStackOrLocal())) {
invalidReturnTypeError(returnedType, m);
}
}
}
} while ((ih = ih.getNext()) != null);
}
}
|