@SuppressWarnings("unused") private static void printClass(final byte[] classfileBuffer, final String classname) { /* final TraceClassVisitor v = new TraceClassVisitor(new PrintWriter(System.out)); new ClassReader(classfileBuffer).accept(v, ClassReader.SKIP_DEBUG); */ final ClassNode cn = new ClassNode(); final ClassReader cr = new ClassReader(classfileBuffer); //cr.accept(new CheckClassAdapter(cn), ClassReader.SKIP_DEBUG); cr.accept(new CheckClassAdapter(cn), 0); for (final Object methodObj : cn.methods) { final MethodNode method = (MethodNode) methodObj; final Analyzer a = new Analyzer(new BasicVerifier()); //final Analyzer a = new Analyzer(new SimpleVerifier()); try { a.analyze(cn.name, method); } catch (final AnalyzerException e) { System.err.println("// error in method " + classname + "." + method.name + method.desc + ":" + e); } printMethod(a, System.err, method); } }
/** * Checks a given class. * * @param cr * a <code>ClassReader</code> that contains bytecode for the * analysis. * @param loader * a <code>ClassLoader</code> which will be used to load * referenced classes. This is useful if you are verifiying * multiple interdependent classes. * @param dump * true if bytecode should be printed out not only when errors * are found. * @param pw * write where results going to be printed */ public static void verify(final ClassReader cr, final ClassLoader loader, final boolean dump, final PrintWriter pw) { ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); Type syperType = cn.superName == null ? null : Type .getObjectType(cn.superName); List<MethodNode> methods = cn.methods; List<Type> interfaces = new ArrayList<Type>(); for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) { interfaces.add(Type.getObjectType(i.next())); } for (int i = 0; i < methods.size(); ++i) { MethodNode method = methods.get(i); SimpleVerifier verifier = new SimpleVerifier( Type.getObjectType(cn.name), syperType, interfaces, (cn.access & Opcodes.ACC_INTERFACE) != 0); Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier); if (loader != null) { verifier.setClassLoader(loader); } try { a.analyze(cn.name, method); if (!dump) { continue; } } catch (Exception e) { e.printStackTrace(pw); } printAnalyzerResult(method, a, pw); } pw.flush(); }
static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a, final PrintWriter pw) { Frame<BasicValue>[] frames = a.getFrames(); Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); pw.println(method.name + method.desc); for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); StringBuilder sb = new StringBuilder(); Frame<BasicValue> f = frames[j]; if (f == null) { sb.append('?'); } else { for (int k = 0; k < f.getLocals(); ++k) { sb.append(getShortName(f.getLocal(k).toString())) .append(' '); } sb.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { sb.append(getShortName(f.getStack(k).toString())) .append(' '); } } while (sb.length() < method.maxStack + method.maxLocals + 1) { sb.append(' '); } pw.print(Integer.toString(j + 100000).substring(1)); pw.print(" " + sb + " : " + t.text.get(t.text.size() - 1)); } for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { method.tryCatchBlocks.get(j).accept(mv); pw.print(" " + t.text.get(t.text.size() - 1)); } pw.println(); }
/** * Constructs a new {@link CheckMethodAdapter} object. This method adapter * will perform basic data flow checks. For instance in a method whose * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the * invalid sequence IADD L2I will be detected. * * @param access * the method's access flags. * @param name * the method's name. * @param desc * the method's descriptor (see {@link Type Type}). * @param cmv * the method visitor to which this adapter must delegate calls. * @param labels * a map of already visited labels (in other methods). */ public CheckMethodAdapter(final int access, final String name, final String desc, final MethodVisitor cmv, final Map<Label, Integer> labels) { this(new MethodNode(Opcodes.ASM5, access, name, desc, null, null) { @Override public void visitEnd() { Analyzer<BasicValue> a = new Analyzer<BasicValue>( new BasicVerifier()); try { a.analyze("dummy", this); } catch (Exception e) { if (e instanceof IndexOutOfBoundsException && maxLocals == 0 && maxStack == 0) { throw new RuntimeException( "Data flow checking option requires valid, non zero maxLocals and maxStack values."); } e.printStackTrace(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); CheckClassAdapter.printAnalyzerResult(this, a, pw); pw.close(); throw new RuntimeException(e.getMessage() + ' ' + sw.toString()); } accept(cmv); } }, labels); this.access = access; }
public InstrumentMethod(MethodDatabase db, String className, MethodNode mn) throws AnalyzerException { this.db = db; this.className = className; this.mn = mn; try { Analyzer a = new TypeAnalyzer(db); this.frames = a.analyze(className, mn); this.lvarStack = mn.maxLocals; this.firstLocal = ((mn.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) ? 0 : 1; } catch (UnsupportedOperationException ex) { throw new AnalyzerException(null, ex.getMessage(), ex); } }
private Frame[] getArrayFrames(MethodNode mn) { try { Analyzer a = new Analyzer(new BooleanArrayInterpreter()); a.analyze(cn.name, mn); return a.getFrames(); } catch (Exception e) { logger.info("[Array] Error during analysis: " + e); return null; } }
private void getFrames(MethodNode mn, String className) { try { Analyzer a = new Analyzer(new BooleanValueInterpreter(mn.desc, (mn.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC)); a.analyze(className, mn); this.frames = a.getFrames(); } catch (Exception e) { logger.info("1. Error during analysis: " + e); //e.printStackTrace(); // TODO: Handle error } }
public void visitEnd() { checkCallSites(); if (instructions.size() == 0 || labels.size() == 0) { accept(mv); return; } this.stackRecorderVar = maxLocals; try { moveNew(); analyzer = new Analyzer(new FastClassVerifier()) { @Override protected Frame newFrame(final int nLocals, final int nStack) { return new MonitoringFrame(nLocals, nStack); } @Override protected Frame newFrame(final Frame src) { return new MonitoringFrame(src); } }; analyzer.analyze(className, this); accept(new ContinuableMethodVisitor(this)); } catch (final AnalyzerException ex) { throw new RuntimeException(ex); } }
public void visitEnd() { if (instructions.size() == 0 || labels.size() == 0) { accept(mv); return; } this.stackRecorderVar = maxLocals; try { moveNew(); analyzer = new Analyzer(new FastClassVerifier()) { @Override protected Frame newFrame(final int nLocals, final int nStack) { return new MonitoringFrame(nLocals, nStack); } @Override protected Frame newFrame(final Frame src) { return new MonitoringFrame(src); } }; analyzer.analyze(className, this); accept(new ContinuableMethodVisitor(this)); } catch (final AnalyzerException ex) { throw new RuntimeException(ex); } }
/** * Constructs a new {@link CheckMethodAdapter} object. This method adapter * will perform basic data flow checks. For instance in a method whose * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the * invalid sequence IADD L2I will be detected. * * @param access * the method's access flags. * @param name * the method's name. * @param desc * the method's descriptor (see {@link Type Type}). * @param cmv * the method visitor to which this adapter must delegate calls. * @param labels * a map of already visited labels (in other methods). */ public CheckMethodAdapter(final int access, final String name, final String desc, final MethodVisitor cmv, final Map<Label, Integer> labels) { this(new MethodNode(Opcodes.ASM5, null, access, name, desc, null, null) { @Override public void visitEnd() { Analyzer<BasicValue> a = new Analyzer<BasicValue>( new BasicVerifier()); try { a.analyze("dummy", this); } catch (Exception e) { if (e instanceof IndexOutOfBoundsException && maxLocals == 0 && maxStack == 0) { throw new RuntimeException( "Data flow checking option requires valid, non zero maxLocals and maxStack values."); } e.printStackTrace(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); CheckClassAdapter.printAnalyzerResult(this, a, pw); pw.close(); throw new RuntimeException(e.getMessage() + ' ' + sw.toString()); } accept(cmv); } }, labels); this.access = access; }
/** * Checks a given class. * * @param cr * a <code>ClassReader</code> that contains bytecode for the * analysis. * @param loader * a <code>ClassLoader</code> which will be used to load * referenced classes. This is useful if you are verifiying * multiple interdependent classes. * @param dump * true if bytecode should be printed out not only when errors * are found. * @param pw * write where results going to be printed */ public static void verify(final ClassReader cr, final ClassLoader loader, final boolean dump, final PrintWriter pw) { ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); Type syperType = cn.superName == null ? null : Type .getObjectType(cn.superName); List<MethodNode> methods = cn.methods; List<Type> interfaces = new ArrayList<Type>(); for (Iterator<String> i = cn.interfaces.iterator(); i.hasNext();) { interfaces.add(Type.getObjectType(i.next().toString())); } for (int i = 0; i < methods.size(); ++i) { MethodNode method = methods.get(i); SimpleVerifier verifier = new SimpleVerifier( Type.getObjectType(cn.name), syperType, interfaces, (cn.access & Opcodes.ACC_INTERFACE) != 0); Analyzer<BasicValue> a = new Analyzer<BasicValue>(verifier); if (loader != null) { verifier.setClassLoader(loader); } try { a.analyze(cn.name, method); if (!dump) { continue; } } catch (Exception e) { e.printStackTrace(pw); } printAnalyzerResult(method, a, pw); } pw.flush(); }
static void printAnalyzerResult(MethodNode method, Analyzer<BasicValue> a, final PrintWriter pw) { Frame<BasicValue>[] frames = a.getFrames(); Textifier t = new Textifier(); TraceMethodVisitor mv = new TraceMethodVisitor(t); pw.println(method.name + method.desc); for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); StringBuffer s = new StringBuffer(); Frame<BasicValue> f = frames[j]; if (f == null) { s.append('?'); } else { for (int k = 0; k < f.getLocals(); ++k) { s.append(getShortName(f.getLocal(k).toString())) .append(' '); } s.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { s.append(getShortName(f.getStack(k).toString())) .append(' '); } } while (s.length() < method.maxStack + method.maxLocals + 1) { s.append(' '); } pw.print(Integer.toString(j + 100000).substring(1)); pw.print(" " + s + " : " + t.text.get(t.text.size() - 1)); } for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { method.tryCatchBlocks.get(j).accept(mv); pw.print(" " + t.text.get(t.text.size() - 1)); } pw.println(); }
/** * Constructs a new {@link CheckMethodAdapter} object. This method adapter * will perform basic data flow checks. For instance in a method whose * signature is <tt>void m ()</tt>, the invalid instruction IRETURN, or the * invalid sequence IADD L2I will be detected. * * @param access * the method's access flags. * @param name * the method's name. * @param desc * the method's descriptor (see {@link Type Type}). * @param cmv * the method visitor to which this adapter must delegate calls. * @param labels * a map of already visited labels (in other methods). */ public CheckMethodAdapter(final int access, final String name, final String desc, final MethodVisitor cmv, final Map<Label, Integer> labels) { this(new MethodNode(access, name, desc, null, null) { @Override public void visitEnd() { Analyzer<BasicValue> a = new Analyzer<BasicValue>( new BasicVerifier()); try { a.analyze("dummy", this); } catch (Exception e) { if (e instanceof IndexOutOfBoundsException && maxLocals == 0 && maxStack == 0) { throw new RuntimeException( "Data flow checking option requires valid, non zero maxLocals and maxStack values."); } e.printStackTrace(); StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw, true); CheckClassAdapter.printAnalyzerResult(this, a, pw); pw.close(); throw new RuntimeException(e.getMessage() + ' ' + sw.toString()); } accept(cmv); } }, labels); this.access = access; }
public static void verifyMethodIntegrity(String ownerInternalName, MethodNode method) { try { new Analyzer(new SimpleVerifier()).analyze(ownerInternalName, method); } catch (AnalyzerException e) { throw new RuntimeException( "Integrity error in method '" + method.name + "' of type '" + ownerInternalName + "': ", e); } }
public static void verifyMethodIntegrity(final String ownerInternalName, final MethodNode method) { try { new Analyzer(new SimpleVerifier()).analyze(ownerInternalName, method); } catch (AnalyzerException e) { throw new RuntimeException( "Integrity error in method '" + method.name + "' of type '" + ownerInternalName + "': ", e); } }
public boolean evaluate() { ilist.add(new InsnNode(Opcodes.RETURN)); Analyzer<ConstValue> constAnalyzer = new Analyzer<ConstValue>( ConstInterpreter.getInstance()); Map<AbstractInsnNode, Frame<ConstValue>> frames = FrameHelper .createMapping(constAnalyzer, PartialEvaluator.class.getName(), method); boolean isOptimized = conditionalReduction(frames); isOptimized |= replaceLoadWithLDC(frames); boolean removed; do { removed = false; removed |= removeDeadStore(); removed |= removePop(); } while (removed); isOptimized |= removed; isOptimized |= removeUnusedJump(); isOptimized |= removeUnusedHandler(); ilist.remove(ilist.getLast()); return isOptimized; }
public static <V extends Value> Frame<V>[] getFrames(Analyzer<V> analyzer, String clazz, MethodNode method) { try { analyzer.analyze(clazz, method); } catch (AnalyzerException e) { throw new DiSLFatalException("Cause by AnalyzerException : \n" + e.getMessage()); } return analyzer.getFrames(); }
private boolean checkClass(final byte[] newClassfileBuffer, final String classname, byte[] origClassfileBuffer) { final ClassNode cn = new ClassNode(); final ClassReader cr = new ClassReader(newClassfileBuffer); //cr.accept(new CheckClassAdapter(cn), ClassReader.SKIP_DEBUG); cr.accept(new CheckClassAdapter(cn), 0); for (final Object methodObj : cn.methods) { final MethodNode method = (MethodNode) methodObj; final Analyzer a = new Analyzer(new BasicVerifier()); // SimpleVerifier has problems with sub-classes, e.g. you cannot use PrintStream for Appendable and so on... //final Analyzer a = new Analyzer(new SimpleVerifier( // Type.getObjectType(cn.name), Type.getObjectType(cn.superName), // (cn.access & Opcodes.ACC_INTERFACE) != 0)); try { a.analyze(cn.name, method); } catch (final AnalyzerException e) { System.err.println("Error in method " + classname + "." + method.name + method.desc + ": " + e); //e.printStackTrace(System.err); printMethod(a, System.err, method); if (newClassfileBuffer == origClassfileBuffer) { System.err.println("This is the original bytecode!"); } else { System.err.println("original bytecode:"); ClassReader origClassReader = new ClassReader(origClassfileBuffer); ClassNode origClassNode = new ClassNode(); origClassReader.accept(origClassNode, 0); for (Object origMethodObj : origClassNode.methods) { MethodNode origMethod = (MethodNode) origMethodObj; if (origMethod.name.equals(method.name) && origMethod.desc.equals(method.desc)) printMethod(System.err, origMethod); } } return false; } } return true; }
private static void printMethod(final Analyzer a, final PrintStream out, final MethodNode method) { final Frame[] frames = a.getFrames(); final Textifier textifier = new Textifier(); final TraceMethodVisitor mv = new TraceMethodVisitor(textifier); out.println(method.name + method.desc); for (int j = 0; j < method.instructions.size(); ++j) { method.instructions.get(j).accept(mv); final StringBuffer s = new StringBuffer(); final Frame f = frames[j]; if (f == null) { s.append('?'); } else { for (int k = 0; k < f.getLocals(); ++k) { s.append(getShortName(f.getLocal(k).toString())).append(' '); } s.append(" : "); for (int k = 0; k < f.getStackSize(); ++k) { s.append(getShortName(f.getStack(k).toString())).append(' '); } } while (s.length() < method.maxStack + method.maxLocals + 1) { s.append(' '); } out.print(Integer.toString(j + 100000).substring(1)); out.print(" " + s + " : " + textifier.text.get(j)); } for (int j = 0; j < method.tryCatchBlocks.size(); ++j) { ((TryCatchBlockNode) method.tryCatchBlocks.get(j)).accept(mv); out.print(" " + textifier.text.get(method.instructions.size()+j)); } out.println(" MAXSTACK " + method.maxStack); out.println(" MAXLOCALS " + method.maxLocals); out.println(); }