List of usage examples for org.objectweb.asm.tree AbstractInsnNode getOpcode
public int getOpcode()
From source file:com.android.tools.lint.checks.FieldGetterDetector.java
License:Apache License
@Override public void checkInstruction(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method, @NonNull AbstractInsnNode instruction) { // As of Gingerbread/API 9, Dalvik performs this optimization automatically if (context.getProject().getMinSdk() >= 9) { return;/*from ww w. ja v a2 s .c om*/ } if ((method.access & Opcodes.ACC_STATIC) != 0) { // Not an instance method return; } if (instruction.getOpcode() != Opcodes.INVOKEVIRTUAL) { return; } MethodInsnNode node = (MethodInsnNode) instruction; String name = node.name; String owner = node.owner; AbstractInsnNode prev = LintUtils.getPrevInstruction(instruction); if (prev == null || prev.getOpcode() != Opcodes.ALOAD) { return; } VarInsnNode prevVar = (VarInsnNode) prev; if (prevVar.var != 0) { // Not on "this", variable 0 in instance methods? return; } if (((name.startsWith("get") && name.length() > 3 //$NON-NLS-1$ && Character.isUpperCase(name.charAt(3))) || (name.startsWith("is") && name.length() > 2 //$NON-NLS-1$ && Character.isUpperCase(name.charAt(2)))) && owner.equals(classNode.name)) { // Calling a potential getter method on self. We now need to // investigate the method body of the getter call and make sure // it's really a plain getter, not just a method which happens // to have a method name like a getter, or a method which not // only returns a field but possibly computes it or performs // other initialization or side effects. This is done in a // second pass over the bytecode, initiated by the finish() // method. if (mPendingCalls == null) { mPendingCalls = new ArrayList<Entry>(); } mPendingCalls.add(new Entry(name, node, method)); } super.checkInstruction(context, classNode, method, instruction); }
From source file:com.android.tools.lint.checks.JavaScriptInterfaceDetector.java
License:Apache License
@Nullable private String findFirstArgType(ClassContext context, ClassNode classNode, MethodNode method, MethodInsnNode call) {//from w w w. jav a2 s . c o m // Find object being passed in as the first argument Analyzer analyzer = new Analyzer(new SourceInterpreter() { @Override public SourceValue newOperation(AbstractInsnNode insn) { if (insn.getOpcode() == Opcodes.NEW) { String desc = ((TypeInsnNode) insn).desc; return new TypeValue(1, desc); } return super.newOperation(insn); } @Override public SourceValue newValue(Type type) { if (type != null && type.getSort() == Type.VOID) { return null; } else if (type != null) { return new TypeValue(1, type.getInternalName()); } return super.newValue(type); } @Override public SourceValue copyOperation(AbstractInsnNode insn, SourceValue value) { return value; } }); try { Frame[] frames = analyzer.analyze(classNode.name, method); InsnList instructions = method.instructions; Frame frame = frames[instructions.indexOf(call)]; if (frame.getStackSize() <= 1) { return null; } SourceValue stackValue = (SourceValue) frame.getStack(1); if (stackValue instanceof TypeValue) { return ((TypeValue) stackValue).getFqcn(); } } catch (AnalyzerException e) { context.log(e, null); } return null; }
From source file:com.android.tools.lint.checks.LocaleDetector.java
License:Apache License
@Override public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method, @NonNull MethodInsnNode call) {//from w w w .ja v a2 s .com String owner = call.owner; String desc = call.desc; String name = call.name; if (owner.equals(DATE_FORMAT_OWNER)) { if (!name.equals(CONSTRUCTOR_NAME)) { return; } if (desc.equals("(Ljava/lang/String;Ljava/text/DateFormatSymbols;)V") //$NON-NLS-1$ || desc.equals("()V") //$NON-NLS-1$ || desc.equals("(Ljava/lang/String;)V")) { //$NON-NLS-1$ Location location = context.getLocation(call); String message = "To get local formatting use getDateInstance(), getDateTimeInstance(), " + "or getTimeInstance(), or use new SimpleDateFormat(String template, " + "Locale locale) with for example Locale.US for ASCII dates."; context.report(DATE_FORMAT, method, call, location, message, null); } return; } else if (!owner.equals(STRING_OWNER)) { return; } if (name.equals(FORMAT_METHOD)) { // Only check the non-locale version of String.format if (!desc.equals("(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;")) { //$NON-NLS-1$ return; } // Find the formatting string Analyzer analyzer = new Analyzer(new SourceInterpreter() { @Override public SourceValue newOperation(AbstractInsnNode insn) { if (insn.getOpcode() == Opcodes.LDC) { Object cst = ((LdcInsnNode) insn).cst; if (cst instanceof String) { return new StringValue(1, (String) cst); } } return super.newOperation(insn); } }); try { Frame[] frames = analyzer.analyze(classNode.name, method); InsnList instructions = method.instructions; Frame frame = frames[instructions.indexOf(call)]; if (frame.getStackSize() == 0) { return; } SourceValue stackValue = (SourceValue) frame.getStack(0); if (stackValue instanceof StringValue) { String format = ((StringValue) stackValue).getString(); if (format != null && StringFormatDetector.isLocaleSpecific(format)) { Location location = context.getLocation(call); String message = "Implicitly using the default locale is a common source of bugs: " + "Use String.format(Locale, ...) instead"; context.report(STRING_LOCALE, method, call, location, message, null); } } } catch (AnalyzerException e) { context.log(e, null); } } else { if (desc.equals("()Ljava/lang/String;")) { //$NON-NLS-1$ Location location = context.getLocation(call); String message = String.format("Implicitly using the default locale is a common source of bugs: " + "Use %1$s(Locale) instead", name); context.report(STRING_LOCALE, method, call, location, message, null); } } }
From source file:com.android.tools.lint.checks.SecureRandomDetector.java
License:Apache License
private static void checkValidSetSeed(ClassContext context, MethodInsnNode call) { assert call.name.equals(SET_SEED); // Make sure the argument passed is not a literal AbstractInsnNode prev = LintUtils.getPrevInstruction(call); if (prev == null) { return;/* w ww . j a v a2 s .co m*/ } int opcode = prev.getOpcode(); if (opcode == Opcodes.LCONST_0 || opcode == Opcodes.LCONST_1 || opcode == Opcodes.LDC) { context.report(ISSUE, context.getLocation(call), "Do not call setSeed() on a SecureRandom with a fixed seed: " + "it is not secure. Use getSeed().", null); } else if (opcode == Opcodes.INVOKESTATIC) { String methodName = ((MethodInsnNode) prev).name; if (methodName.equals("currentTimeMillis") || methodName.equals("nanoTime")) { context.report(ISSUE, context.getLocation(call), "It is dangerous to seed SecureRandom with the current time because " + "that value is more predictable to an attacker than the default seed.", null); } } }
From source file:com.android.tools.lint.checks.SecureRandomGeneratorDetector.java
License:Apache License
@Override public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method, @NonNull MethodInsnNode call) {/*from www . jav a 2 s . c o m*/ if (mIgnore) { return; } String owner = call.owner; String name = call.name; // Look for the workaround code: if we see a Class.forName on the harmony NativeCrypto, // we'll consider that a sign. if (name.equals(FOR_NAME)) { if (call.getOpcode() != Opcodes.INVOKESTATIC || !owner.equals(JAVA_LANG_CLASS)) { return; } AbstractInsnNode prev = LintUtils.getPrevInstruction(call); if (prev instanceof LdcInsnNode) { Object cst = ((LdcInsnNode) prev).cst; //noinspection SpellCheckingInspection if (cst instanceof String && "org.apache.harmony.xnet.provider.jsse.NativeCrypto".equals(cst)) { mIgnore = true; } } return; } // Look for calls that probably require a properly initialized random number generator. assert owner.equals(JAVAX_CRYPTO_KEY_GENERATOR) || owner.equals(JAVA_SECURITY_KEY_PAIR_GENERATOR) || owner.equals(JAVAX_CRYPTO_KEY_AGREEMENT) || owner.equals(OWNER_SECURE_RANDOM) || owner.equals(JAVAX_CRYPTO_CIPHER) || owner.equals(JAVAX_CRYPTO_SIGNATURE) || owner.equals(JAVAX_NET_SSL_SSLENGINE) : owner; boolean warn = false; if (owner.equals(JAVAX_CRYPTO_SIGNATURE)) { warn = name.equals(INIT_SIGN); } else if (owner.equals(JAVAX_CRYPTO_CIPHER)) { if (name.equals(INIT)) { int arity = getDescArity(call.desc); AbstractInsnNode node = call; for (int i = 0; i < arity; i++) { node = LintUtils.getPrevInstruction(node); if (node == null) { break; } } if (node != null) { int opcode = node.getOpcode(); if (opcode == Opcodes.ICONST_3 || // Cipher.WRAP_MODE opcode == Opcodes.ICONST_1) { // Cipher.ENCRYPT_MODE warn = true; } } } } else if (name.equals(GET_INSTANCE) || name.equals(CONSTRUCTOR_NAME) || name.equals(WRAP) || name.equals(UNWRAP)) { // For SSLEngine warn = true; } if (warn) { if (mLocation != null) { return; } if (context.getMainProject().getMinSdk() > 18) { // Fix no longer needed mIgnore = true; return; } if (context.getDriver().isSuppressed(ISSUE, classNode, method, call)) { mIgnore = true; } else { mLocation = context.getLocation(call); } } }
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 w ww .j a va 2 s. com*/ } 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.WakelockDetector.java
License:Apache License
@Override public void checkCall(@NonNull ClassContext context, @NonNull ClassNode classNode, @NonNull MethodNode method, @NonNull MethodInsnNode call) {/*from ww w .ja v a2 s .c o m*/ if (!context.getProject().getReportIssues()) { // If this is a library project not being analyzed, ignore it return; } if (call.owner.equals(WAKELOCK_OWNER)) { String name = call.name; if (name.equals(ACQUIRE_METHOD)) { mHasAcquire = true; if (context.getDriver().getPhase() == 2) { assert !mHasRelease; context.report(ISSUE, method, call, context.getLocation(call), "Found a wakelock acquire() but no release() calls anywhere", null); } else { assert context.getDriver().getPhase() == 1; // Perform flow analysis in this method to see if we're // performing an acquire/release block, where there are code paths // between the acquire and release which can result in the // release call not getting reached. checkFlow(context, classNode, method, call); } } else if (name.equals(RELEASE_METHOD)) { mHasRelease = true; // See if the release is happening in an onDestroy method, in an // activity. if ("onDestroy".equals(method.name) //$NON-NLS-1$ && context.getDriver().isSubclassOf(classNode, ANDROID_APP_ACTIVITY)) { context.report(ISSUE, method, call, context.getLocation(call), "Wakelocks should be released in onPause, not onDestroy", null); } } } else if (call.owner.equals(POWER_MANAGER)) { if (call.name.equals(NEW_WAKE_LOCK_METHOD)) { AbstractInsnNode prev = LintUtils.getPrevInstruction(call); if (prev == null) { return; } prev = LintUtils.getPrevInstruction(prev); if (prev == null || prev.getOpcode() != Opcodes.LDC) { return; } LdcInsnNode ldc = (LdcInsnNode) prev; Object constant = ldc.cst; if (constant instanceof Integer) { int flag = ((Integer) constant).intValue(); // Constant values are copied into the bytecode so we have to compare // values; however, that means the values are part of the API final int PARTIAL_WAKE_LOCK = 0x00000001; final int ACQUIRE_CAUSES_WAKEUP = 0x10000000; final int both = PARTIAL_WAKE_LOCK | ACQUIRE_CAUSES_WAKEUP; if ((flag & both) == both) { context.report(ISSUE, method, call, context.getLocation(call), "Should not set both PARTIAL_WAKE_LOCK and ACQUIRE_CAUSES_WAKEUP. " + "If you do not want the screen to turn on, get rid of " + "ACQUIRE_CAUSES_WAKEUP", null); } } } } }
From source file:com.android.tools.lint.checks.WakelockDetector.java
License:Apache License
/** Search from the given node towards the target; return false if we reach * an exit point such as a return or a call on the way there that is not within * a try/catch clause./*from w ww . j av a 2s . c om*/ * * @param node the current node * @return true if the target was reached * XXX RETURN VALUES ARE WRONG AS OF RIGHT NOW */ protected int dfs(ControlFlowGraph.Node node) { AbstractInsnNode instruction = node.instruction; if (instruction.getType() == AbstractInsnNode.JUMP_INSN) { int opcode = instruction.getOpcode(); if (opcode == Opcodes.RETURN || opcode == Opcodes.ARETURN || opcode == Opcodes.LRETURN || opcode == Opcodes.IRETURN || opcode == Opcodes.DRETURN || opcode == Opcodes.FRETURN || opcode == Opcodes.ATHROW) { if (DEBUG) { System.out.println("Found exit via explicit return: " //$NON-NLS-1$ + node.toString(false)); } return SEEN_RETURN; } } if (!DEBUG) { // There are no cycles, so no *NEED* for this, though it does avoid // researching shared labels. However, it makes debugging harder (no re-entry) // so this is only done when debugging is off if (node.visit != 0) { return 0; } node.visit = 1; } // Look for the target. This is any method call node which is a release on the // lock (later also check it's the same instance, though that's harder). // This is because finally blocks tend to be inlined so from a single try/catch/finally // with a release() in the finally, the bytecode can contain multiple repeated // (inlined) release() calls. if (instruction.getType() == AbstractInsnNode.METHOD_INSN) { MethodInsnNode method = (MethodInsnNode) instruction; if (method.name.equals(RELEASE_METHOD) && method.owner.equals(WAKELOCK_OWNER)) { return SEEN_TARGET; } else if (method.name.equals(ACQUIRE_METHOD) && method.owner.equals(WAKELOCK_OWNER)) { // OK } else if (method.name.equals(IS_HELD_METHOD) && method.owner.equals(WAKELOCK_OWNER)) { // OK } else { // Some non acquire/release method call: if this is not associated with a // try-catch block, it would mean the exception would exit the method, // which would be an error if (node.exceptions == null || node.exceptions.isEmpty()) { // Look up the corresponding frame, if any AbstractInsnNode curr = method.getPrevious(); boolean foundFrame = false; while (curr != null) { if (curr.getType() == AbstractInsnNode.FRAME) { foundFrame = true; break; } curr = curr.getPrevious(); } if (!foundFrame) { if (DEBUG) { System.out.println("Found exit via unguarded method call: " //$NON-NLS-1$ + node.toString(false)); } return SEEN_RETURN; } } } } // if (node.instruction is a call, and the call is not caught by // a try/catch block (provided the release is not inside the try/catch block) // then return false int status = 0; boolean implicitReturn = true; List<Node> successors = node.successors; List<Node> exceptions = node.exceptions; if (exceptions != null) { if (!exceptions.isEmpty()) { implicitReturn = false; } for (Node successor : exceptions) { status = dfs(successor) | status; if ((status & SEEN_RETURN) != 0) { if (DEBUG) { System.out.println("Found exit via exception: " //$NON-NLS-1$ + node.toString(false)); } return status; } } if (status != 0) { status |= SEEN_EXCEPTION; } } if (successors != null) { if (!successors.isEmpty()) { implicitReturn = false; if (successors.size() > 1) { status |= SEEN_BRANCH; } } for (Node successor : successors) { status = dfs(successor) | status; if ((status & SEEN_RETURN) != 0) { if (DEBUG) { System.out.println("Found exit via branches: " //$NON-NLS-1$ + node.toString(false)); } return status; } } } if (implicitReturn) { status |= SEEN_RETURN; if (DEBUG) { System.out.println("Found exit: via implicit return: " //$NON-NLS-1$ + node.toString(false)); } } return status; }
From source file:com.android.tools.lint.client.api.LintDriver.java
License:Apache License
@Nullable private static MethodInsnNode findConstructorInvocation(@NonNull MethodNode method, @NonNull String className) { InsnList nodes = ((MethodNode) 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 . jav a 2 s .c o m*/ } } return null; }
From source file:com.builtbroken.mc.patch.ASMUtility.java
/** * Prints out all the info about a method * * @param methodNode - method/*from ww w . j a va 2s .co m*/ */ public static void printMethod(MethodNode methodNode) { //TODO print rest of information ListIterator<AbstractInsnNode> it = methodNode.instructions.iterator(); while (it.hasNext()) { AbstractInsnNode next = it.next(); if (next instanceof MethodInsnNode) { System.out.println("MethodInsnNode( " + next.getOpcode() + ", " + ((MethodInsnNode) next).name + ((MethodInsnNode) next).desc + " )"); } else if (next instanceof VarInsnNode) { System.out.println("VarInsnNode( " + next.getOpcode() + ", " + ((VarInsnNode) next).var + " )"); } else if (next instanceof LabelNode) { System.out.println("LabelNode( " + ((LabelNode) next).getLabel() + " )"); } else if (next instanceof LineNumberNode) { System.out.println("LineNumberNode( " + ((LineNumberNode) next).line + " )"); } else { System.out.println(next); } } }