@Override public void visitGotoInstruction(GotoInstruction ins) { isBranch = true; InstructionHandle target = ins.getTarget(); if (target == null) throw new IllegalStateException(); targetList.add(new Target(target, GOTO_EDGE)); }
private void findIfElseDuplicates(CFG cfg, Method method, BasicBlock bb) { BasicBlock thenBB = null, elseBB = null; Iterator<Edge> iei = cfg.outgoingEdgeIterator(bb); while (iei.hasNext()) { Edge e = iei.next(); if (e.getType() == EdgeTypes.IFCMP_EDGE) { elseBB = e.getTarget(); } else if (e.getType() == EdgeTypes.FALL_THROUGH_EDGE) { thenBB = e.getTarget(); } } if ((thenBB == null) || (elseBB == null)) return; InstructionHandle thenStartHandle = getDeepFirstInstruction(cfg, thenBB); InstructionHandle elseStartHandle = getDeepFirstInstruction(cfg, elseBB); if ((thenStartHandle == null) || (elseStartHandle == null)) return; int thenStartPos = thenStartHandle.getPosition(); int elseStartPos = elseStartHandle.getPosition(); InstructionHandle thenFinishIns = findThenFinish(cfg, thenBB, elseStartPos); int thenFinishPos = thenFinishIns.getPosition(); if (!(thenFinishIns.getInstruction() instanceof GotoInstruction)) return; InstructionHandle elseFinishHandle = ((GotoInstruction) thenFinishIns.getInstruction()).getTarget(); int elseFinishPos = elseFinishHandle.getPosition(); if (thenFinishPos >= elseStartPos) return; if ((thenFinishPos - thenStartPos) != (elseFinishPos - elseStartPos)) return; if (thenFinishPos <= thenStartPos) return; byte[] thenBytes = getCodeBytes(method, thenStartPos, thenFinishPos); byte[] elseBytes = getCodeBytes(method, elseStartPos, elseFinishPos); if (!Arrays.equals(thenBytes, elseBytes)) return; // adjust elseFinishPos to be inclusive (for source line attribution) InstructionHandle elseLastIns = elseFinishHandle.getPrev(); if (elseLastIns != null) elseFinishPos = elseLastIns.getPosition(); pendingBugs.add(new BugInstance(this, "DB_DUPLICATE_BRANCHES", NORMAL_PRIORITY) .addClassAndMethod(classContext.getJavaClass(), method) .addSourceLineRange(classContext, this, thenStartPos, thenFinishPos) .addSourceLineRange(classContext, this, elseStartPos, elseFinishPos)); }
/** * These are the checks if constraints are satisfied which are described in the * Java Virtual Machine Specification, Second Edition as Static Constraints on * the instructions of Java Virtual Machine Code (chapter 4.8.1). * * @throws StaticCodeConstraintException if the verification fails. */ private void pass3StaticInstructionChecks(){ // Code array must not be empty: // Enforced in pass 2 (also stated in the static constraints of the Code // array in vmspec2), together with pass 1 (reading code_length bytes and // interpreting them as code[]). So this must not be checked again here. if (! (code.getCode().length < 65536)){// contradicts vmspec2 page 152 ("Limitations"), but is on page 134. throw new StaticCodeInstructionConstraintException("Code array in code attribute '"+code+"' too big: must be smaller than 65536 bytes."); } // First opcode at offset 0: okay, that's clear. Nothing to do. // Only instances of the instructions documented in Section 6.4 may appear in // the code array. // For BCEL's sake, we cannot handle WIDE stuff, but hopefully BCEL does its job right :) // The last byte of the last instruction in the code array must be the byte at index // code_length-1 : See the do_verify() comments. We actually don't iterate through the // byte array, but use an InstructionList so we cannot check for this. But BCEL does // things right, so it's implicitly okay. // TODO: Check how BCEL handles (and will handle) instructions like IMPDEP1, IMPDEP2, // BREAKPOINT... that BCEL knows about but which are illegal anyway. // We currently go the safe way here. InstructionHandle ih = instructionList.getStart(); while (ih != null){ Instruction i = ih.getInstruction(); if (i instanceof IMPDEP1){ throw new StaticCodeInstructionConstraintException("IMPDEP1 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); } if (i instanceof IMPDEP2){ throw new StaticCodeInstructionConstraintException("IMPDEP2 must not be in the code, it is an illegal instruction for _internal_ JVM use!"); } if (i instanceof BREAKPOINT){ throw new StaticCodeInstructionConstraintException("BREAKPOINT must not be in the code, it is an illegal instruction for _internal_ JVM use!"); } ih = ih.getNext(); } // The original verifier seems to do this check here, too. // An unreachable last instruction may also not fall through the // end of the code, which is stupid -- but with the original // verifier's subroutine semantics one cannot predict reachability. Instruction last = instructionList.getEnd().getInstruction(); if (! ((last instanceof ReturnInstruction) || (last instanceof RET) || (last instanceof GotoInstruction) || (last instanceof ATHROW) )) { throw new StaticCodeInstructionConstraintException("Execution must not fall off the bottom of the code array. This constraint is enforced statically as some existing verifiers do - so it may be a false alarm if the last instruction is not reachable."); } }
/** * A utility method that calculates the successors of a given InstructionHandle * <B>in the same subroutine</B>. That means, a RET does not have any successors * as defined here. A JsrInstruction has its physical successor as its successor * (opposed to its target) as defined here. */ private static InstructionHandle[] getSuccessors(InstructionHandle instruction){ final InstructionHandle[] empty = new InstructionHandle[0]; final InstructionHandle[] single = new InstructionHandle[1]; final InstructionHandle[] pair = new InstructionHandle[2]; Instruction inst = instruction.getInstruction(); if (inst instanceof RET){ return empty; } // Terminates method normally. if (inst instanceof ReturnInstruction){ return empty; } // Terminates method abnormally, because JustIce mandates // subroutines not to be protected by exception handlers. if (inst instanceof ATHROW){ return empty; } // See method comment. if (inst instanceof JsrInstruction){ single[0] = instruction.getNext(); return single; } if (inst instanceof GotoInstruction){ single[0] = ((GotoInstruction) inst).getTarget(); return single; } if (inst instanceof BranchInstruction){ if (inst instanceof Select){ // BCEL's getTargets() returns only the non-default targets, // thanks to Eli Tilevich for reporting. InstructionHandle[] matchTargets = ((Select) inst).getTargets(); InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; ret[0] = ((Select) inst).getTarget(); System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); return ret; } else{ pair[0] = instruction.getNext(); pair[1] = ((BranchInstruction) inst).getTarget(); return pair; } } // default case: Fall through. single[0] = instruction.getNext(); return single; }
/** * A utility method that calculates the successors of a given InstructionHandle * <B>in the same subroutine</B>. That means, a RET does not have any successors * as defined here. A JsrInstruction has its physical successor as its successor * (opposed to its target) as defined here. */ private static InstructionHandle[] getSuccessors(InstructionHandle instruction){ Instruction inst = instruction.getInstruction(); if (inst instanceof RET){ return empty; } // Terminates method normally. if (inst instanceof ReturnInstruction){ return empty; } // Terminates method abnormally, because JustIce mandates // subroutines not to be protected by exception handlers. if (inst instanceof ATHROW){ return empty; } final InstructionHandle[] single = new InstructionHandle[1]; // See method comment. if (inst instanceof JsrInstruction){ single[0] = instruction.getNext(); return single; } if (inst instanceof GotoInstruction){ single[0] = ((GotoInstruction) inst).getTarget(); return single; } if (inst instanceof BranchInstruction){ if (inst instanceof Select){ // BCEL's getTargets() returns only the non-default targets, // thanks to Eli Tilevich for reporting. InstructionHandle[] matchTargets = ((Select) inst).getTargets(); InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; ret[0] = ((Select) inst).getTarget(); System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); return ret; } else{ final InstructionHandle[] pair = new InstructionHandle[2]; pair[0] = instruction.getNext(); pair[1] = ((BranchInstruction) inst).getTarget(); return pair; } } // default case: Fall through. single[0] = instruction.getNext(); return single; }
/** * A utility method that calculates the successors of a given InstructionHandle * That means, a RET does have successors as defined here. * A JsrInstruction has its target as its successor * (opposed to its physical successor) as defined here. */ // TODO: implement caching! private InstructionHandle[] _getSuccessors(){ final InstructionHandle[] empty = new InstructionHandle[0]; final InstructionHandle[] single = new InstructionHandle[1]; final InstructionHandle[] pair = new InstructionHandle[2]; Instruction inst = getInstruction().getInstruction(); if (inst instanceof RET){ Subroutine s = subroutines.subroutineOf(getInstruction()); if (s==null){ //return empty; // RET in dead code. "empty" would be the correct answer, but we know something about the surrounding project... throw new AssertionViolatedException("Asking for successors of a RET in dead code?!"); } //TODO: remove throw new AssertionViolatedException("DID YOU REALLY WANT TO ASK FOR RET'S SUCCS?"); /* InstructionHandle[] jsrs = s.getEnteringJsrInstructions(); InstructionHandle[] ret = new InstructionHandle[jsrs.length]; for (int i=0; i<jsrs.length; i++){ ret[i] = jsrs[i].getNext(); } return ret; */ } // Terminates method normally. if (inst instanceof ReturnInstruction){ return empty; } // Terminates method abnormally, because JustIce mandates // subroutines not to be protected by exception handlers. if (inst instanceof ATHROW){ return empty; } // See method comment. if (inst instanceof JsrInstruction){ single[0] = ((JsrInstruction) inst).getTarget(); return single; } if (inst instanceof GotoInstruction){ single[0] = ((GotoInstruction) inst).getTarget(); return single; } if (inst instanceof BranchInstruction){ if (inst instanceof Select){ // BCEL's getTargets() returns only the non-default targets, // thanks to Eli Tilevich for reporting. InstructionHandle[] matchTargets = ((Select) inst).getTargets(); InstructionHandle[] ret = new InstructionHandle[matchTargets.length+1]; ret[0] = ((Select) inst).getTarget(); System.arraycopy(matchTargets, 0, ret, 1, matchTargets.length); return ret; } else{ pair[0] = getInstruction().getNext(); pair[1] = ((BranchInstruction) inst).getTarget(); return pair; } } // default case: Fall through. single[0] = getInstruction().getNext(); return single; }