Example usage for org.objectweb.asm.tree InsnList get

List of usage examples for org.objectweb.asm.tree InsnList get

Introduction

In this page you can find the example usage for org.objectweb.asm.tree InsnList get.

Prototype

public AbstractInsnNode get(final int index) 

Source Link

Document

Returns the instruction whose index is given.

Usage

From source file:com.android.tools.klint.client.api.LintDriver.java

License:Apache License

@Nullable
private static MethodInsnNode findConstructorInvocation(@NonNull MethodNode method, @NonNull String className) {
    InsnList nodes = method.instructions;
    for (int i = 0, n = nodes.size(); i < n; i++) {
        AbstractInsnNode instruction = nodes.get(i);
        if (instruction.getOpcode() == Opcodes.INVOKESPECIAL) {
            MethodInsnNode call = (MethodInsnNode) instruction;
            if (className.equals(call.owner)) {
                return call;
            }//  w  w  w  . java 2  s  .c o m
        }
    }

    return null;
}

From source file:com.android.tools.lint.checks.AllowAllHostnameVerifierDetector.java

License:Apache License

@SuppressWarnings("rawtypes")
@Override/* www  .j  ava2  s . c om*/
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (!classNode.interfaces.contains("javax/net/ssl/HostnameVerifier")) {
        return;
    }
    List methodList = classNode.methods;
    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;
        if ("verify".equals(method.name)) {
            InsnList nodes = method.instructions;
            boolean emptyMethod = true; // Stays true if method has no instructions
                                        // other than ICONST_1 or IRETURN.
            boolean containsIconst1 = false;

            for (int i = 0, n = nodes.size(); i < n; i++) {
                // Future work: Improve this check to be less sensitive to irrelevant
                // instructions/statements/invocations (e.g. System.out.println).
                AbstractInsnNode instruction = nodes.get(i);
                int type = instruction.getType();
                if (type != AbstractInsnNode.LABEL && type != AbstractInsnNode.LINE
                        && !(type == AbstractInsnNode.INSN && (instruction.getOpcode() == Opcodes.ICONST_1
                                || instruction.getOpcode() == Opcodes.IRETURN))) {
                    emptyMethod = false;
                    break;
                } else if (type == AbstractInsnNode.INSN && instruction.getOpcode() == Opcodes.ICONST_1) {
                    containsIconst1 = true;
                }
            }
            if (containsIconst1 && emptyMethod) {
                Location location = context.getLocation(method, classNode);
                context.report(ISSUE, location,
                        method.name + " always returns true, which "
                                + "could cause insecure network traffic due to trusting TLS/SSL "
                                + "server certificates for wrong hostnames");
            }
        }
    }
}

From source file:com.android.tools.lint.checks.ApiDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
@Override//from  w w w.ja v a 2s.  c om
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (mApiDatabase == null) {
        return;
    }

    if (AOSP_BUILD && classNode.name.startsWith("android/support/")) { //$NON-NLS-1$
        return;
    }

    // Requires util package (add prebuilts/tools/common/asm-tools/asm-debug-all-4.0.jar)
    //classNode.accept(new TraceClassVisitor(new PrintWriter(System.out)));

    int classMinSdk = getClassMinSdk(context, classNode);
    if (classMinSdk == -1) {
        classMinSdk = getMinSdk(context);
    }

    List methodList = classNode.methods;
    if (methodList.isEmpty()) {
        return;
    }

    boolean checkCalls = context.isEnabled(UNSUPPORTED) || context.isEnabled(INLINED);
    boolean checkMethods = context.isEnabled(OVERRIDE) && context.getMainProject().getBuildSdk() >= 1;
    String frameworkParent = null;
    if (checkMethods) {
        LintDriver driver = context.getDriver();
        String owner = classNode.superName;
        while (owner != null) {
            // For virtual dispatch, walk up the inheritance chain checking
            // each inherited method
            if ((owner.startsWith("android/") //$NON-NLS-1$
                    && !owner.startsWith("android/support/")) //$NON-NLS-1$
                    || owner.startsWith("java/") //$NON-NLS-1$
                    || owner.startsWith("javax/")) { //$NON-NLS-1$
                frameworkParent = owner;
                break;
            }
            owner = driver.getSuperClass(owner);
        }
        if (frameworkParent == null) {
            checkMethods = false;
        }
    }

    if (checkCalls) { // Check implements/extends
        if (classNode.superName != null) {
            String signature = classNode.superName;
            checkExtendsClass(context, classNode, classMinSdk, signature);
        }
        if (classNode.interfaces != null) {
            @SuppressWarnings("unchecked") // ASM API
            List<String> interfaceList = classNode.interfaces;
            for (String signature : interfaceList) {
                checkExtendsClass(context, classNode, classMinSdk, signature);
            }
        }
    }

    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;

        int minSdk = getLocalMinSdk(method.invisibleAnnotations);
        if (minSdk == -1) {
            minSdk = classMinSdk;
        }

        InsnList nodes = method.instructions;

        if (checkMethods && Character.isJavaIdentifierStart(method.name.charAt(0))) {
            int buildSdk = context.getMainProject().getBuildSdk();
            String name = method.name;
            assert frameworkParent != null;
            int api = mApiDatabase.getCallVersion(frameworkParent, name, method.desc);
            if (api > buildSdk && buildSdk != -1) {
                // TODO: Don't complain if it's annotated with @Override; that means
                // somehow the build target isn't correct.
                String fqcn;
                String owner = classNode.name;
                if (CONSTRUCTOR_NAME.equals(name)) {
                    fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
                } else {
                    fqcn = ClassContext.getFqcn(owner) + '#' + name;
                }
                String message = String.format(
                        "This method is not overriding anything with the current build "
                                + "target, but will in API level %1$d (current target is %2$d): %3$s",
                        api, buildSdk, fqcn);

                Location location = context.getLocation(method, classNode);
                context.report(OVERRIDE, method, null, location, message, null);
            }
        }

        if (!checkCalls) {
            continue;
        }

        if (CHECK_DECLARATIONS) {
            // Check types in parameter list and types of local variables
            List localVariables = method.localVariables;
            if (localVariables != null) {
                for (Object v : localVariables) {
                    LocalVariableNode var = (LocalVariableNode) v;
                    String desc = var.desc;
                    if (desc.charAt(0) == 'L') {
                        // "Lpackage/Class;" => "package/Bar"
                        String className = desc.substring(1, desc.length() - 1);
                        int api = mApiDatabase.getClassVersion(className);
                        if (api > minSdk) {
                            String fqcn = ClassContext.getFqcn(className);
                            String message = String.format(
                                    "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk,
                                    fqcn);
                            report(context, message, var.start, method,
                                    className.substring(className.lastIndexOf('/') + 1), null,
                                    SearchHints.create(NEAREST).matchJavaSymbol());
                        }
                    }
                }
            }

            // Check return type
            // The parameter types are already handled as local variables so we can skip
            // right to the return type.
            // Check types in parameter list
            String signature = method.desc;
            if (signature != null) {
                int args = signature.indexOf(')');
                if (args != -1 && signature.charAt(args + 1) == 'L') {
                    String type = signature.substring(args + 2, signature.length() - 1);
                    int api = mApiDatabase.getClassVersion(type);
                    if (api > minSdk) {
                        String fqcn = ClassContext.getFqcn(type);
                        String message = String.format(
                                "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);
                        AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
                        report(context, message, first, method, method.name, null,
                                SearchHints.create(BACKWARD).matchJavaSymbol());
                    }
                }
            }
        }

        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            int type = instruction.getType();
            if (type == AbstractInsnNode.METHOD_INSN) {
                MethodInsnNode node = (MethodInsnNode) instruction;
                String name = node.name;
                String owner = node.owner;
                String desc = node.desc;

                // No need to check methods in this local class; we know they
                // won't be an API match
                if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) {
                    owner = classNode.superName;
                }

                boolean checkingSuperClass = false;
                while (owner != null) {
                    int api = mApiDatabase.getCallVersion(owner, name, desc);
                    if (api > minSdk) {
                        if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
                            // We're in a compiler-generated method to generate an
                            // array indexed by enum ordinal values to enum values. The enum
                            // itself must be requiring a higher API number than is
                            // currently used, but the call site for the switch statement
                            // will also be referencing it, so no need to report these
                            // calls.
                            break;
                        }

                        if (!checkingSuperClass && node.getOpcode() == Opcodes.INVOKEVIRTUAL
                                && methodDefinedLocally(classNode, name, desc)) {
                            break;
                        }

                        String fqcn;
                        if (CONSTRUCTOR_NAME.equals(name)) {
                            fqcn = "new " + ClassContext.getFqcn(owner); //$NON-NLS-1$
                        } else {
                            fqcn = ClassContext.getFqcn(owner) + '#' + name;
                        }
                        String message = String.format(
                                "Call requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);

                        if (name.equals(ORDINAL_METHOD) && instruction.getNext() != null
                                && instruction.getNext().getNext() != null
                                && instruction.getNext().getOpcode() == Opcodes.IALOAD
                                && instruction.getNext().getNext().getOpcode() == Opcodes.TABLESWITCH) {
                            message = String.format(
                                    "Enum for switch requires API level %1$d " + "(current min is %2$d): %3$s",
                                    api, minSdk, ClassContext.getFqcn(owner));
                        }

                        report(context, message, node, method, name, null,
                                SearchHints.create(FORWARD).matchJavaSymbol());
                    }

                    // For virtual dispatch, walk up the inheritance chain checking
                    // each inherited method
                    if (owner.startsWith("android/") //$NON-NLS-1$
                            || owner.startsWith("javax/")) { //$NON-NLS-1$
                        // The API map has already inlined all inherited methods
                        // so no need to keep checking up the chain
                        // -- unless it's the support library which is also in
                        // the android/ namespace:
                        if (owner.startsWith("android/support/")) { //$NON-NLS-1$
                            owner = context.getDriver().getSuperClass(owner);
                        } else {
                            owner = null;
                        }
                    } else if (owner.startsWith("java/")) { //$NON-NLS-1$
                        if (owner.equals(LocaleDetector.DATE_FORMAT_OWNER)) {
                            checkSimpleDateFormat(context, method, node, minSdk);
                        }
                        // Already inlined; see comment above
                        owner = null;
                    } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
                        owner = context.getDriver().getSuperClass(owner);
                    } else if (node.getOpcode() == Opcodes.INVOKESTATIC && api == -1) {
                        // Inherit through static classes as well
                        owner = context.getDriver().getSuperClass(owner);
                    } else {
                        owner = null;
                    }

                    checkingSuperClass = true;
                }
            } else if (type == AbstractInsnNode.FIELD_INSN) {
                FieldInsnNode node = (FieldInsnNode) instruction;
                String name = node.name;
                String owner = node.owner;
                int api = mApiDatabase.getFieldVersion(owner, name);
                if (api > minSdk) {
                    if (method.name.startsWith(SWITCH_TABLE_PREFIX)) {
                        checkSwitchBlock(context, classNode, node, method, name, owner, api, minSdk);
                        continue;
                    }
                    String fqcn = ClassContext.getFqcn(owner) + '#' + name;
                    if (mPendingFields != null) {
                        mPendingFields.remove(fqcn);
                    }
                    String message = String.format("Field requires API level %1$d (current min is %2$d): %3$s",
                            api, minSdk, fqcn);
                    report(context, message, node, method, name, null,
                            SearchHints.create(FORWARD).matchJavaSymbol());
                }
            } else if (type == AbstractInsnNode.LDC_INSN) {
                LdcInsnNode node = (LdcInsnNode) instruction;
                if (node.cst instanceof Type) {
                    Type t = (Type) node.cst;
                    String className = t.getInternalName();

                    int api = mApiDatabase.getClassVersion(className);
                    if (api > minSdk) {
                        String fqcn = ClassContext.getFqcn(className);
                        String message = String.format(
                                "Class requires API level %1$d (current min is %2$d): %3$s", api, minSdk, fqcn);
                        report(context, message, node, method,
                                className.substring(className.lastIndexOf('/') + 1), null,
                                SearchHints.create(FORWARD).matchJavaSymbol());
                    }
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.ApiDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
private static void checkSwitchBlock(ClassContext context, ClassNode classNode, FieldInsnNode field,
        MethodNode method, String name, String owner, int api, int minSdk) {
    // Switch statements on enums are tricky. The compiler will generate a method
    // which returns an array of the enum constants, indexed by their ordinal() values.
    // However, we only want to complain if the code is actually referencing one of
    // the non-available enum fields.
    ///*from   www.j  a v  a 2s .c  o m*/
    // For the android.graphics.PorterDuff.Mode enum for example, the first few items
    // in the array are populated like this:
    //
    //   L0
    //    ALOAD 0
    //    GETSTATIC android/graphics/PorterDuff$Mode.ADD : Landroid/graphics/PorterDuff$Mode;
    //    INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
    //    ICONST_1
    //    IASTORE
    //   L1
    //    GOTO L3
    //   L2
    //   FRAME FULL [[I] [java/lang/NoSuchFieldError]
    //    POP
    //   L3
    //   FRAME SAME
    //    ALOAD 0
    //    GETSTATIC android/graphics/PorterDuff$Mode.CLEAR : Landroid/graphics/PorterDuff$Mode;
    //    INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
    //    ICONST_2
    //    IASTORE
    //    ...
    // So if we for example find that the "ADD" field isn't accessible, since it requires
    // API 11, we need to
    //   (1) First find out what its ordinal number is. We can look at the following
    //       instructions to discover this; it's the "ICONST_1" and "IASTORE" instructions.
    //       (After ICONST_5 it moves on to BIPUSH 6, BIPUSH 7, etc.)
    //   (2) Find the corresponding *usage* of this switch method. For the above enum,
    //       the switch ordinal lookup method will be called
    //         "$SWITCH_TABLE$android$graphics$PorterDuff$Mode" with desc "()[I".
    //       This means we will be looking for an invocation in some other method which looks
    //       like this:
    //         INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I
    //       (obviously, it can be invoked more than once)
    //       Note that it can be used more than once in this class and all sites should be
    //       checked!
    //   (3) Look up the corresponding table switch, which should look something like this:
    //        INVOKESTATIC (current class).$SWITCH_TABLE$android$graphics$PorterDuff$Mode ()[I
    //        ALOAD 0
    //        INVOKEVIRTUAL android/graphics/PorterDuff$Mode.ordinal ()I
    //        IALOAD
    //        LOOKUPSWITCH
    //          2: L1
    //          11: L2
    //          default: L3
    //       Here we need to see if the LOOKUPSWITCH instruction is referencing our target
    //       case. Above we were looking for the "ADD" case which had ordinal 1. Since this
    //       isn't explicitly referenced, we can ignore this field reference.
    AbstractInsnNode next = field.getNext();
    if (next == null || next.getOpcode() != Opcodes.INVOKEVIRTUAL) {
        return;
    }
    next = next.getNext();
    if (next == null) {
        return;
    }
    int ordinal;
    switch (next.getOpcode()) {
    case Opcodes.ICONST_0:
        ordinal = 0;
        break;
    case Opcodes.ICONST_1:
        ordinal = 1;
        break;
    case Opcodes.ICONST_2:
        ordinal = 2;
        break;
    case Opcodes.ICONST_3:
        ordinal = 3;
        break;
    case Opcodes.ICONST_4:
        ordinal = 4;
        break;
    case Opcodes.ICONST_5:
        ordinal = 5;
        break;
    case Opcodes.BIPUSH: {
        IntInsnNode iin = (IntInsnNode) next;
        ordinal = iin.operand;
        break;
    }
    default:
        return;
    }

    // Find usages of this call site
    List methodList = classNode.methods;
    for (Object m : methodList) {
        InsnList nodes = ((MethodNode) m).instructions;
        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            if (instruction.getOpcode() != Opcodes.INVOKESTATIC) {
                continue;
            }
            MethodInsnNode node = (MethodInsnNode) instruction;
            if (node.name.equals(method.name) && node.desc.equals(method.desc)
                    && node.owner.equals(classNode.name)) {
                // Find lookup switch
                AbstractInsnNode target = getNextInstruction(node);
                while (target != null) {
                    if (target.getOpcode() == Opcodes.LOOKUPSWITCH) {
                        LookupSwitchInsnNode lookup = (LookupSwitchInsnNode) target;
                        @SuppressWarnings("unchecked") // ASM API
                        List<Integer> keys = lookup.keys;
                        if (keys != null && keys.contains(ordinal)) {
                            String fqcn = ClassContext.getFqcn(owner) + '#' + name;
                            String message = String.format(
                                    "Enum value requires API level %1$d " + "(current min is %2$d): %3$s", api,
                                    minSdk, fqcn);
                            report(context, message, lookup, (MethodNode) m, name, null,
                                    SearchHints.create(FORWARD).matchJavaSymbol());

                            // Break out of the inner target search only; the switch
                            // statement could be used in other places in this class as
                            // well and we want to report all problematic usages.
                            break;
                        }
                    }
                    target = getNextInstruction(target);
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.ControlFlowGraph.java

License:Apache License

/**
 * Creates a new {@link ControlFlowGraph} and populates it with the flow
 * control for the given method. If the optional {@code initial} parameter is
 * provided with an existing graph, then the graph is simply populated, not
 * created. This allows subclassing of the graph instance, if necessary.
 *
 * @param initial usually null, but can point to an existing instance of a
 *            {@link ControlFlowGraph} in which that graph is reused (but
 *            populated with new edges)/*w  w  w. jav  a2s  . co m*/
 * @param classNode the class containing the method to be analyzed
 * @param method the method to be analyzed
 * @return a {@link ControlFlowGraph} with nodes for the control flow in the
 *         given method
 * @throws AnalyzerException if the underlying bytecode library is unable to
 *             analyze the method bytecode
 */
@NonNull
public static ControlFlowGraph create(@Nullable ControlFlowGraph initial, @NonNull ClassNode classNode,
        @NonNull MethodNode method) throws AnalyzerException {
    final ControlFlowGraph graph = initial != null ? initial : new ControlFlowGraph();
    final InsnList instructions = method.instructions;
    graph.mNodeMap = Maps.newHashMapWithExpectedSize(instructions.size());

    // Create a flow control graph using ASM4's analyzer. According to the ASM 4 guide
    // (download.forge.objectweb.org/asm/asm4-guide.pdf) there are faster ways to construct
    // it, but those require a lot more code.
    Analyzer analyzer = new Analyzer(new BasicInterpreter()) {
        @Override
        protected void newControlFlowEdge(int insn, int successor) {
            // Update the information as of whether the this object has been
            // initialized at the given instruction.
            AbstractInsnNode from = instructions.get(insn);
            AbstractInsnNode to = instructions.get(successor);
            graph.add(from, to);
        }

        @Override
        protected boolean newControlFlowExceptionEdge(int insn, TryCatchBlockNode tcb) {
            AbstractInsnNode from = instructions.get(insn);
            graph.exception(from, tcb);
            return super.newControlFlowExceptionEdge(insn, tcb);
        }

        @Override
        protected boolean newControlFlowExceptionEdge(int insn, int successor) {
            AbstractInsnNode from = instructions.get(insn);
            AbstractInsnNode to = instructions.get(successor);
            graph.exception(from, to);
            return super.newControlFlowExceptionEdge(insn, successor);
        }
    };

    analyzer.analyze(classNode.name, method);
    return graph;
}

From source file:com.android.tools.lint.checks.CordovaVersionDetector.java

License:Apache License

@Override
public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) {
    //noinspection VariableNotUsedInsideIf
    if (mCordovaVersion != null) {
        // Exit early if we have already found the cordova version in the JS file.
        // This will be the case for all versions > 3.x.x
        return;/*from   ww  w . j  a  v  a  2  s . c o  m*/
    }

    // For cordova versions such as 2.7.1, the version is a static *non-final* field in
    // a class named Device. Since it is non-final, it is initialized in the <clinit> method.
    // Example:
    //
    // ldc           #5                  // String 2.7.1
    // putstatic     #6                  // Field cordovaVersion:Ljava/lang/String;
    // ...
    if (classNode.name.equals(FQN_CORDOVA_DEVICE)) {
        //noinspection unchecked ASM api.
        List<MethodNode> methods = classNode.methods;
        for (MethodNode method : methods) {
            if (SdkConstants.CLASS_CONSTRUCTOR.equals(method.name)) {
                InsnList nodes = method.instructions;
                for (int i = 0, n = nodes.size(); i < n; i++) {
                    AbstractInsnNode instruction = nodes.get(i);
                    int type = instruction.getType();
                    if (type == AbstractInsnNode.FIELD_INSN) {
                        checkInstructionInternal(context, classNode, instruction);
                        break;
                    }
                }
            }
        }
    } else if (classNode.name.equals(FQN_CORDOVA_WEBVIEW)) {
        // For versions > 3.x.x, the version string is stored as a static final String in
        // CordovaWebView.
        // Note that this is also stored in the cordova.js.* but from a lint api perspective,
        // it's much faster to look it up here than load and check in the JS file.
        // e.g.
        //   public static final java.lang.String CORDOVA_VERSION;
        //      descriptor: Ljava/lang/String;
        //      flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL
        //      ConstantValue: String 4.1.1
        //
        //noinspection unchecked ASM api.
        List<FieldNode> fields = classNode.fields;
        for (FieldNode node : fields) {
            if (FIELD_NAME_CORDOVA_VERSION_WEBVIEW.equals(node.name)
                    && (node.access & Opcodes.ACC_FINAL) == Opcodes.ACC_FINAL // is final
                    && (node.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC // is static
                    && node.value instanceof String) {
                mCordovaVersion = createVersion((String) node.value);
                if (mCordovaVersion != null) {
                    validateCordovaVersion(context, mCordovaVersion, context.getLocation(classNode));
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.InvalidPackageDetector.java

License:Apache License

@SuppressWarnings("rawtypes") // ASM API
@Override//from w  ww.  j a v  a2  s.c  o  m
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (!context.isFromClassLibrary() || shouldSkip(context.file)) {
        return;
    }

    if (mApiDatabase == null) {
        return;
    }

    if (classNode.name.startsWith(JAVAX_PKG_PREFIX)) {
        mJavaxLibraryClasses.add(classNode.name);
    }

    List methodList = classNode.methods;
    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;

        InsnList nodes = method.instructions;

        // Check return type
        // The parameter types are already handled as local variables so we can skip
        // right to the return type.
        // Check types in parameter list
        String signature = method.desc;
        if (signature != null) {
            int args = signature.indexOf(')');
            if (args != -1 && signature.charAt(args + 1) == 'L') {
                String type = signature.substring(args + 2, signature.length() - 1);
                if (isInvalidPackage(type)) {
                    AbstractInsnNode first = nodes.size() > 0 ? nodes.get(0) : null;
                    record(context, method, first, type);
                }
            }
        }

        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            int type = instruction.getType();
            if (type == AbstractInsnNode.METHOD_INSN) {
                MethodInsnNode node = (MethodInsnNode) instruction;
                String owner = node.owner;

                // No need to check methods in this local class; we know they
                // won't be an API match
                if (node.getOpcode() == Opcodes.INVOKEVIRTUAL && owner.equals(classNode.name)) {
                    owner = classNode.superName;
                }

                while (owner != null) {
                    if (isInvalidPackage(owner)) {
                        record(context, method, instruction, owner);
                    }

                    // For virtual dispatch, walk up the inheritance chain checking
                    // each inherited method
                    if (owner.startsWith("android/") //$NON-NLS-1$
                            || owner.startsWith(JAVA_PKG_PREFIX) || owner.startsWith(JAVAX_PKG_PREFIX)) {
                        owner = null;
                    } else if (node.getOpcode() == Opcodes.INVOKEVIRTUAL) {
                        owner = context.getDriver().getSuperClass(owner);
                    } else if (node.getOpcode() == Opcodes.INVOKESTATIC) {
                        // Inherit through static classes as well
                        owner = context.getDriver().getSuperClass(owner);
                    } else {
                        owner = null;
                    }
                }
            } else if (type == AbstractInsnNode.FIELD_INSN) {
                FieldInsnNode node = (FieldInsnNode) instruction;
                String owner = node.owner;
                if (isInvalidPackage(owner)) {
                    record(context, method, instruction, owner);
                }
            } else if (type == AbstractInsnNode.LDC_INSN) {
                LdcInsnNode node = (LdcInsnNode) instruction;
                if (node.cst instanceof Type) {
                    Type t = (Type) node.cst;
                    String className = t.getInternalName();
                    if (isInvalidPackage(className)) {
                        record(context, method, instruction, className);
                    }
                }
            }
        }
    }
}

From source file:com.android.tools.lint.checks.TrustAllX509TrustManagerDetector.java

License:Apache License

@Override
@SuppressWarnings("rawtypes")
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    if (!context.isFromClassLibrary()) {
        // Non-library code checked at the AST level
        return;//from   ww w  .  j  a v  a 2 s . c  o  m
    }
    if (!classNode.interfaces.contains("javax/net/ssl/X509TrustManager")) {
        return;
    }
    List methodList = classNode.methods;
    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;
        if ("checkServerTrusted".equals(method.name) || "checkClientTrusted".equals(method.name)) {
            InsnList nodes = method.instructions;
            boolean emptyMethod = true; // Stays true if method doesn't perform any "real"
                                        // operations
            for (int i = 0, n = nodes.size(); i < n; i++) {
                // Future work: Improve this check to be less sensitive to irrelevant
                // instructions/statements/invocations (e.g. System.out.println) by
                // looking for calls that could lead to a CertificateException being
                // thrown, e.g. throw statement within the method itself or invocation
                // of another method that may throw a CertificateException, and only
                // reporting an issue if none of these calls are found. ControlFlowGraph
                // may be useful here.
                AbstractInsnNode instruction = nodes.get(i);
                int type = instruction.getType();
                if (type != AbstractInsnNode.LABEL && type != AbstractInsnNode.LINE
                        && !(type == AbstractInsnNode.INSN && instruction.getOpcode() == Opcodes.RETURN)) {
                    emptyMethod = false;
                    break;
                }
            }
            if (emptyMethod) {
                Location location = context.getLocation(method, classNode);
                context.report(ISSUE, location, getErrorMessage(method.name));
            }
        }
    }
}

From source file:com.android.tools.lint.checks.UnsafeBroadcastReceiverDetector.java

License:Apache License

@SuppressWarnings("rawtypes")
public void checkClass(@NonNull final ClassContext context, @NonNull ClassNode classNode) {
    // If class isn't in mReceiversWithIntentFilter (set below by
    // XmlScanner), skip it.
    if (!mReceiversWithProtectedBroadcastIntentFilter.contains(classNode.name)) {
        return;/*from w  w w.j a va2s .  c o  m*/
    }

    // Search for "void onReceive(android.content.Context, android.content.Intent)" method
    List methodList = classNode.methods;

    for (Object m : methodList) {
        MethodNode method = (MethodNode) m;
        if (!"onReceive".equals(method.name)
                || !"(Landroid/content/Context;Landroid/content/Intent;)V".equals(method.desc)) {
            continue;
        }
        // Search for call to getAction but also search for references to aload_2,
        // which indicates that the method is making use of the received intent in
        // some way.
        //
        // If the onReceive method doesn't call getAction but does make use of
        // the received intent, it is possible that it is passing it to another
        // method that might be performing the getAction check, so we warn that the
        // finding may be a false positive. (An alternative option would be to not
        // report a finding at all in this case.)
        boolean getActionEncountered = false;
        boolean intentParameterEncountered = false;
        InsnList nodes = method.instructions;
        for (int i = 0, n = nodes.size(); i < n; i++) {
            AbstractInsnNode instruction = nodes.get(i);
            int type = instruction.getType();
            if (type == AbstractInsnNode.VAR_INSN) {
                VarInsnNode node = (VarInsnNode) instruction;
                if (node.getOpcode() == Opcodes.ALOAD) {
                    if (node.var == 2) {
                        intentParameterEncountered = true;
                    }
                }
            } else if (type == AbstractInsnNode.METHOD_INSN) {
                MethodInsnNode node = (MethodInsnNode) instruction;
                if ("android/content/Intent".equals(node.owner) && "getAction".equals(node.name)) {
                    getActionEncountered = true;
                    break;
                }
            }
        }
        if (!getActionEncountered) {
            Location location = context.getLocation(method, classNode);
            String report;
            if (!intentParameterEncountered) {
                report = "This broadcast receiver declares an intent-filter for a protected "
                        + "broadcast action string, which can only be sent by the system, "
                        + "not third-party applications. However, the receiver's onReceive "
                        + "method does not appear to call getAction to ensure that the "
                        + "received Intent's action string matches the expected value, "
                        + "potentially making it possible for another actor to send a "
                        + "spoofed intent with no action string or a different action "
                        + "string and cause undesired behavior.";
            } else {
                // An alternative implementation option is to not report a finding at all in
                // this case, if we are worried about false positives causing confusion or
                // resulting in developers ignoring other lint warnings.
                report = "This broadcast receiver declares an intent-filter for a protected "
                        + "broadcast action string, which can only be sent by the system, "
                        + "not third-party applications. However, the receiver's onReceive "
                        + "method does not appear to call getAction to ensure that the "
                        + "received Intent's action string matches the expected value, "
                        + "potentially making it possible for another actor to send a "
                        + "spoofed intent with no action string or a different action "
                        + "string and cause undesired behavior. In this case, it is "
                        + "possible that the onReceive method passed the received Intent "
                        + "to another method that checked the action string. If so, this "
                        + "finding can safely be ignored.";
            }
            context.report(ACTION_STRING, method, null, location, report);
        }
    }
}

From source file:com.android.tools.lint.checks.WakelockDetector.java

License:Apache License

private void checkFlow(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method,
        @NonNull MethodInsnNode acquire) {
    // Track allocations such that we know whether the type of the call
    // is on a SecureRandom rather than a Random
    final InsnList instructions = method.instructions;
    MethodInsnNode release = null;//from w w w.ja  v a2s.c o m

    // Find release call
    for (int i = 0, n = instructions.size(); i < n; i++) {
        AbstractInsnNode instruction = instructions.get(i);
        int type = instruction.getType();
        if (type == AbstractInsnNode.METHOD_INSN) {
            MethodInsnNode call = (MethodInsnNode) instruction;
            if (call.name.equals(RELEASE_METHOD) && call.owner.equals(WAKELOCK_OWNER)) {
                release = call;
                break;
            }
        }
    }

    if (release == null) {
        // Didn't find both acquire and release in this method; no point in doing
        // local flow analysis
        return;
    }

    try {
        MyGraph graph = new MyGraph();
        ControlFlowGraph.create(graph, classNode, method);

        if (DEBUG) {
            // Requires util package
            //ClassNode clazz = classNode;
            //clazz.accept(new TraceClassVisitor(new PrintWriter(System.out)));
            System.out.println(graph.toString(graph.getNode(acquire)));
        }

        int status = dfs(graph.getNode(acquire));
        if ((status & SEEN_RETURN) != 0) {
            String message;
            if ((status & SEEN_EXCEPTION) != 0) {
                message = "The release() call is not always reached (via exceptional flow)";
            } else {
                message = "The release() call is not always reached";
            }

            context.report(ISSUE, method, acquire, context.getLocation(release), message, null);
        }
    } catch (AnalyzerException e) {
        context.log(e, null);
    }
}