@Override public void visitFile(Path file, String relative) throws IOException { if (file.getFileName().toString().endsWith(".class")) { ClassReader cr = new ClassReader(Files.readAllBytes(file)); ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG | ClassReader.EXPAND_FRAMES | ClassReader.SKIP_FRAMES); for (MethodNode method : cn.methods) { BasicVerifier verifier = new BasicVerifier(); Analyzer<BasicValue> a = new Analyzer<>(verifier); try { a.analyze(cn.name, method); } catch (Exception ex) { System.err.println("Error verify method " + cr.getClassName() + "." + method.name + " " + method.desc); if (detail) { ex.printStackTrace(System.err); printAnalyzerResult(method, a, new PrintWriter(new OutputStreamWriter(System.err, StandardCharsets.UTF_8))); } } } } } });
switch (insn.getOpcode()) { case IALOAD: expected1 = newValue(Type.getType("[I")); expected2 = BasicValue.INT_VALUE; break; case BALOAD: if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { expected1 = newValue(Type.getType("[Z")); } else { expected1 = newValue(Type.getType("[B")); expected1 = newValue(Type.getType("[C")); expected2 = BasicValue.INT_VALUE; break; case SALOAD: expected1 = newValue(Type.getType("[S")); expected2 = BasicValue.INT_VALUE; break; case LALOAD: expected1 = newValue(Type.getType("[J")); expected2 = BasicValue.INT_VALUE; break; case FALOAD: expected1 = newValue(Type.getType("[F")); expected2 = BasicValue.INT_VALUE; break; case DALOAD: expected1 = newValue(Type.getType("[D")); expected2 = BasicValue.INT_VALUE;
break; case GETFIELD: expected = newValue(Type .getObjectType(((FieldInsnNode) insn).owner)); break; if (!isArrayValue(value)) { throw new AnalyzerException(insn, null, "an array reference", value); expected = newValue(Type.getType(((FieldInsnNode) insn).desc)); break; default: throw new Error("Internal error."); if (!isSubTypeOf(value, expected)) { throw new AnalyzerException(insn, null, expected, value);
switch (insn.getOpcode()) { case IASTORE: expected1 = newValue(Type.getType("[I")); expected3 = BasicValue.INT_VALUE; break; case BASTORE: if (isSubTypeOf(value1, newValue(Type.getType("[Z")))) { expected1 = newValue(Type.getType("[Z")); } else { expected1 = newValue(Type.getType("[B")); expected1 = newValue(Type.getType("[C")); expected3 = BasicValue.INT_VALUE; break; case SASTORE: expected1 = newValue(Type.getType("[S")); expected3 = BasicValue.INT_VALUE; break; case LASTORE: expected1 = newValue(Type.getType("[J")); expected3 = BasicValue.LONG_VALUE; break; case FASTORE: expected1 = newValue(Type.getType("[F")); expected3 = BasicValue.FLOAT_VALUE; break; case DASTORE: expected1 = newValue(Type.getType("[D")); expected3 = BasicValue.DOUBLE_VALUE;
@Override public void returnOperation(final AbstractInsnNode insn, final BasicValue value, final BasicValue expected) throws AnalyzerException { if (!isSubTypeOf(value, expected)) { throw new AnalyzerException(insn, "Incompatible return type", expected, value); } }
@Override public BasicValue newValue(final Type type) { if (type == null) { return BasicValue.UNINITIALIZED_VALUE; } boolean isArray = type.getSort() == Type.ARRAY; if (isArray) { switch (type.getElementType().getSort()) { case Type.BOOLEAN: case Type.CHAR: case Type.BYTE: case Type.SHORT: return new BasicValue(type); } } BasicValue v = super.newValue(type); if (BasicValue.REFERENCE_VALUE.equals(v)) { if (isArray) { v = newValue(type.getElementType()); String desc = v.getType().getDescriptor(); for (int i = 0; i < type.getDimensions(); ++i) { desc = '[' + desc; } v = new BasicValue(Type.getType(desc)); } else { v = new BasicValue(type); } } return v; }
if (opcode != INVOKESTATIC && opcode != INVOKEDYNAMIC) { Type owner = Type.getObjectType(((MethodInsnNode) insn).owner); if (!isSubTypeOf(values.get(i++), newValue(owner))) { throw new AnalyzerException(insn, "Method owner", newValue(owner), values.get(0)); Type[] args = Type.getArgumentTypes(desc); while (i < values.size()) { BasicValue expected = newValue(args[j++]); BasicValue encountered = values.get(i++); if (!isSubTypeOf(encountered, expected)) { throw new AnalyzerException(insn, "Argument " + j, expected, encountered);
@SuppressWarnings("rawtypes") public static void verify(final ClassReader cr, PrintWriter out) throws AnalyzerException, IllegalArgumentException, IllegalAccessException { ClassNode cn = new ClassNode(); cr.accept(new CheckClassAdapter(cn, false), ClassReader.SKIP_DEBUG); List methods = cn.methods; for (int i = 0; i < methods.size(); ++i) { MethodNode method = (MethodNode) methods.get(i); List tryCatchBlocks = method.tryCatchBlocks; for (int j = 0; j < tryCatchBlocks.size(); j++) { TryCatchBlockNode tcn = (TryCatchBlockNode) tryCatchBlocks.get(j); if (tcn.start.equals(tcn.end)) { throw new DexException("try/catch block %d in %s has same start(%s) and end(%s)", j, method.name, tcn.start.getLabel(), tcn.end.getLabel()); } } BasicVerifier verifier = new BasicVerifier(); Analyzer a = new Analyzer(verifier); try { a.analyze(cn.name, method); } catch (Exception e) { out.println(cr.getClassName() + "." + method.name + method.desc); printAnalyzerResult(method, a, out); e.printStackTrace(out); out.flush(); throw new DexException("method " + method.name + " " + method.desc, e); } } }
@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);
@Override public void visitEnd() { Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier()); try { analyzer.analyze("dummy", this); } catch (IndexOutOfBoundsException e) { if (maxLocals == 0 && maxStack == 0) { throw new IllegalArgumentException( "Data flow checking option requires valid, non zero maxLocals and maxStack.", e); } throwError(analyzer, e); } catch (AnalyzerException e) { throwError(analyzer, e); } accept(methodVisitor); }
@Override public void visitEnd() { Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(new BasicVerifier()); try { analyzer.analyze("dummy", this); } catch (IndexOutOfBoundsException e) { if (maxLocals == 0 && maxStack == 0) { throw new IllegalArgumentException( "Data flow checking option requires valid, non zero maxLocals and maxStack.", e); } throwError(analyzer, e); } catch (AnalyzerException e) { throwError(analyzer, e); } accept(methodVisitor); }