Search in sources :

Example 1 with AnalyzerException

use of org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException in project intellij-community by JetBrains.

the class BytecodeAnalysisTest method checkLeakingParameters.

private static void checkLeakingParameters(Class<?> jClass) throws IOException {
    final HashMap<Method, boolean[]> map = new HashMap<>();
    // collecting leakedParameters
    final ClassReader classReader = new ClassReader(jClass.getResourceAsStream("/" + jClass.getName().replace('.', '/') + ".class"));
    classReader.accept(new ClassVisitor(Opcodes.API_VERSION) {

        @Override
        public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
            final MethodNode node = new MethodNode(Opcodes.API_VERSION, access, name, desc, signature, exceptions);
            final Method method = new Method(classReader.getClassName(), name, desc);
            return new MethodVisitor(Opcodes.API_VERSION, node) {

                @Override
                public void visitEnd() {
                    super.visitEnd();
                    try {
                        map.put(method, LeakingParameters.build(classReader.getClassName(), node, false).parameters);
                    } catch (AnalyzerException ignore) {
                    }
                }
            };
        }
    }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
    for (java.lang.reflect.Method jMethod : jClass.getDeclaredMethods()) {
        Method method = new Method(Type.getType(jClass).getInternalName(), jMethod.getName(), Type.getMethodDescriptor(jMethod));
        Annotation[][] annotations = jMethod.getParameterAnnotations();
        for (int i = 0; i < annotations.length; i++) {
            boolean isLeaking = false;
            Annotation[] parameterAnnotations = annotations[i];
            for (Annotation parameterAnnotation : parameterAnnotations) {
                if (parameterAnnotation.annotationType() == ExpectLeaking.class) {
                    isLeaking = true;
                }
            }
            assertEquals(method.toString() + " #" + i, isLeaking, map.get(method)[i]);
        }
    }
}
Also used : AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException) HashMap(java.util.HashMap) Annotation(java.lang.annotation.Annotation) MethodNode(org.jetbrains.org.objectweb.asm.tree.MethodNode)

Example 2 with AnalyzerException

use of org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException in project intellij-community by JetBrains.

the class LiteAnalyzer method analyze.

public Frame<V>[] analyze(final String owner, final MethodNode m) throws AnalyzerException {
    if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0 || m.instructions.size() == 0) {
        frames = (Frame<V>[]) new Frame<?>[0];
        return frames;
    }
    int n = m.instructions.size();
    InsnList insns = m.instructions;
    List<TryCatchBlockNode>[] handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
    frames = (Frame<V>[]) new Frame<?>[n];
    queued = new boolean[n];
    queue = new int[n];
    top = 0;
    // computes exception handlers for each instruction
    for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
        TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
        int begin = insns.indexOf(tcb.start);
        int end = insns.indexOf(tcb.end);
        for (int j = begin; j < end; ++j) {
            List<TryCatchBlockNode> insnHandlers = handlers[j];
            if (insnHandlers == null) {
                insnHandlers = new ArrayList<>();
                handlers[j] = insnHandlers;
            }
            insnHandlers.add(tcb);
        }
    }
    // initializes the data structures for the control flow analysis
    Frame<V> current = new Frame<>(m.maxLocals, m.maxStack);
    Frame<V> handler = new Frame<>(m.maxLocals, m.maxStack);
    current.setReturn(interpreter.newValue(Type.getReturnType(m.desc)));
    Type[] args = Type.getArgumentTypes(m.desc);
    int local = 0;
    if ((m.access & ACC_STATIC) == 0) {
        Type ctype = Type.getObjectType(owner);
        current.setLocal(local++, interpreter.newValue(ctype));
    }
    for (int i = 0; i < args.length; ++i) {
        current.setLocal(local++, interpreter.newValue(args[i]));
        if (args[i].getSize() == 2) {
            current.setLocal(local++, interpreter.newValue(null));
        }
    }
    while (local < m.maxLocals) {
        current.setLocal(local++, interpreter.newValue(null));
    }
    merge(0, current);
    // control flow analysis
    while (top > 0) {
        int insn = queue[--top];
        Frame<V> f = frames[insn];
        queued[insn] = false;
        AbstractInsnNode insnNode = null;
        try {
            insnNode = m.instructions.get(insn);
            int insnOpcode = insnNode.getOpcode();
            int insnType = insnNode.getType();
            if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
                merge(insn + 1, f);
            } else {
                current.init(f).execute(insnNode, interpreter);
                if (insnNode instanceof JumpInsnNode) {
                    JumpInsnNode j = (JumpInsnNode) insnNode;
                    if (insnOpcode != GOTO && insnOpcode != JSR) {
                        merge(insn + 1, current);
                    }
                    int jump = insns.indexOf(j.label);
                    merge(jump, current);
                } else if (insnNode instanceof LookupSwitchInsnNode) {
                    LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
                    int jump = insns.indexOf(lsi.dflt);
                    merge(jump, current);
                    for (int j = 0; j < lsi.labels.size(); ++j) {
                        LabelNode label = lsi.labels.get(j);
                        jump = insns.indexOf(label);
                        merge(jump, current);
                    }
                } else if (insnNode instanceof TableSwitchInsnNode) {
                    TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
                    int jump = insns.indexOf(tsi.dflt);
                    merge(jump, current);
                    for (int j = 0; j < tsi.labels.size(); ++j) {
                        LabelNode label = tsi.labels.get(j);
                        jump = insns.indexOf(label);
                        merge(jump, current);
                    }
                } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
                    merge(insn + 1, current);
                }
            }
            List<TryCatchBlockNode> insnHandlers = handlers[insn];
            if (insnHandlers != null) {
                for (int i = 0; i < insnHandlers.size(); ++i) {
                    TryCatchBlockNode tcb = insnHandlers.get(i);
                    int jump = insns.indexOf(tcb.handler);
                    handler.init(f);
                    handler.clearStack();
                    handler.push(interpreter.newValue(ASMUtils.THROWABLE_TYPE));
                    merge(jump, handler);
                }
            }
        } catch (AnalyzerException e) {
            throw new AnalyzerException(e.node, "Error at instruction " + insn + ": " + e.getMessage(), e);
        } catch (Exception e) {
            throw new AnalyzerException(insnNode, "Error at instruction " + insn + ": " + e.getMessage(), e);
        }
    }
    return frames;
}
Also used : Frame(org.jetbrains.org.objectweb.asm.tree.analysis.Frame) AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException) AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException) Type(org.jetbrains.org.objectweb.asm.Type) List(java.util.List) ArrayList(java.util.ArrayList)

Example 3 with AnalyzerException

use of org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException in project intellij-community by JetBrains.

the class ClassDataIndexer method processClass.

public static Map<Key, List<Equation>> processClass(final ClassReader classReader, final String presentableUrl) {
    // It is OK to share pending states, actions and results for analyses.
    // Analyses are designed in such a way that they first write to states/actions/results and then read only those portion
    // of states/actions/results which were written by the current pass of the analysis.
    // Since states/actions/results are quite expensive to create (32K array) for each analysis, we create them once per class analysis.
    final State[] sharedPendingStates = new State[Analysis.STEPS_LIMIT];
    final PendingAction[] sharedPendingActions = new PendingAction[Analysis.STEPS_LIMIT];
    final PResults.PResult[] sharedResults = new PResults.PResult[Analysis.STEPS_LIMIT];
    final Map<Key, List<Equation>> equations = new HashMap<>();
    classReader.accept(new KeyedMethodVisitor() {

        protected MethodVisitor visitMethod(final MethodNode node, final Key key) {
            return new MethodVisitor(Opcodes.API_VERSION, node) {

                private boolean jsr;

                @Override
                public void visitJumpInsn(int opcode, Label label) {
                    if (opcode == Opcodes.JSR) {
                        jsr = true;
                    }
                    super.visitJumpInsn(opcode, label);
                }

                @Override
                public void visitEnd() {
                    super.visitEnd();
                    equations.put(key, processMethod(node, jsr, key.method, key.stable));
                }
            };
        }

        /**
       * Facade for analysis, it invokes specialized analyses for branching/non-branching methods.
       *
       * @param methodNode asm node for method
       * @param jsr whether a method has jsr instruction
       */
        private List<Equation> processMethod(final MethodNode methodNode, boolean jsr, Method method, boolean stable) {
            ProgressManager.checkCanceled();
            final Type[] argumentTypes = Type.getArgumentTypes(methodNode.desc);
            final Type resultType = Type.getReturnType(methodNode.desc);
            final boolean isReferenceResult = ASMUtils.isReferenceType(resultType);
            final boolean isBooleanResult = ASMUtils.isBooleanType(resultType);
            final boolean isInterestingResult = isReferenceResult || isBooleanResult;
            // 4*n: for each reference parameter: @NotNull IN, @Nullable, null -> ... contract, !null -> contract
            // 3: @NotNull OUT, @Nullable OUT, purity analysis
            List<Equation> equations = new ArrayList<>(argumentTypes.length * 4 + 3);
            equations.add(PurityAnalysis.analyze(method, methodNode, stable));
            if (argumentTypes.length == 0 && !isInterestingResult) {
                // no need to continue analysis
                return equations;
            }
            try {
                final ControlFlowGraph graph = ControlFlowGraph.build(className, methodNode, jsr);
                if (graph.transitions.length > 0) {
                    final DFSTree dfs = DFSTree.build(graph.transitions, graph.edgeCount);
                    boolean branching = !dfs.back.isEmpty();
                    if (!branching) {
                        for (int[] transition : graph.transitions) {
                            if (transition != null && transition.length > 1) {
                                branching = true;
                                break;
                            }
                        }
                    }
                    if (branching) {
                        RichControlFlow richControlFlow = new RichControlFlow(graph, dfs);
                        if (richControlFlow.reducible()) {
                            NegationAnalysis negated = tryNegation(method, argumentTypes, graph, isBooleanResult, dfs, jsr);
                            processBranchingMethod(method, methodNode, richControlFlow, argumentTypes, isReferenceResult, isBooleanResult, stable, jsr, equations, negated);
                            return equations;
                        }
                        LOG.debug(method + ": CFG is not reducible");
                    } else // simple
                    {
                        processNonBranchingMethod(method, argumentTypes, graph, isReferenceResult, isBooleanResult, stable, equations);
                        return equations;
                    }
                }
                return topEquations(method, argumentTypes, isReferenceResult, isInterestingResult, stable);
            } catch (ProcessCanceledException e) {
                throw e;
            } catch (Throwable e) {
                // incorrect bytecode may result in Runtime exceptions during analysis
                // so here we suppose that exception is due to incorrect bytecode
                LOG.debug("Unexpected Error during processing of " + method + " in " + presentableUrl, e);
                return topEquations(method, argumentTypes, isReferenceResult, isInterestingResult, stable);
            }
        }

        private NegationAnalysis tryNegation(final Method method, final Type[] argumentTypes, final ControlFlowGraph graph, final boolean isBooleanResult, final DFSTree dfs, final boolean jsr) throws AnalyzerException {
            class Util {

                boolean isMethodCall(int opCode) {
                    return opCode == Opcodes.INVOKESTATIC || opCode == Opcodes.INVOKESPECIAL || opCode == Opcodes.INVOKEVIRTUAL || opCode == Opcodes.INVOKEINTERFACE;
                }

                boolean singleIfBranch() {
                    int branch = 0;
                    for (int i = 0; i < graph.transitions.length; i++) {
                        int[] transition = graph.transitions[i];
                        if (transition.length == 2) {
                            branch++;
                            int opCode = graph.methodNode.instructions.get(i).getOpcode();
                            boolean isIfInsn = opCode == Opcodes.IFEQ || opCode == Opcodes.IFNE;
                            if (!isIfInsn) {
                                return false;
                            }
                        }
                        if (branch > 1)
                            return false;
                    }
                    return branch == 1;
                }

                boolean singleMethodCall() {
                    int callCount = 0;
                    for (int i = 0; i < graph.transitions.length; i++) {
                        if (isMethodCall(graph.methodNode.instructions.get(i).getOpcode())) {
                            callCount++;
                            if (callCount > 1) {
                                return false;
                            }
                        }
                    }
                    return callCount == 1;
                }

                public boolean booleanConstResult() {
                    try {
                        final boolean[] origins = OriginsAnalysis.resultOrigins(leakingParametersAndFrames(method, graph.methodNode, argumentTypes, jsr).frames, graph.methodNode.instructions, graph);
                        for (int i = 0; i < origins.length; i++) {
                            if (origins[i]) {
                                int opCode = graph.methodNode.instructions.get(i).getOpcode();
                                boolean isBooleanConst = opCode == Opcodes.ICONST_0 || opCode == Opcodes.ICONST_1;
                                if (!isBooleanConst) {
                                    return false;
                                }
                            }
                        }
                        return true;
                    } catch (AnalyzerException ignore) {
                    }
                    return false;
                }
            }
            if (graph.methodNode.instructions.size() < 20 && isBooleanResult && dfs.back.isEmpty() && !jsr) {
                Util util = new Util();
                if (util.singleIfBranch() && util.singleMethodCall() && util.booleanConstResult()) {
                    NegationAnalysis analyzer = new NegationAnalysis(method, graph);
                    try {
                        analyzer.analyze();
                        return analyzer;
                    } catch (NegationAnalysisFailure ignore) {
                        return null;
                    }
                }
            }
            return null;
        }

        private void processBranchingMethod(final Method method, final MethodNode methodNode, final RichControlFlow richControlFlow, Type[] argumentTypes, boolean isReferenceResult, boolean isBooleanResult, final boolean stable, boolean jsr, List<Equation> result, NegationAnalysis negatedAnalysis) throws AnalyzerException {
            boolean isInterestingResult = isBooleanResult || isReferenceResult;
            boolean maybeLeakingParameter = isInterestingResult;
            for (Type argType : argumentTypes) {
                if (ASMUtils.isReferenceType(argType)) {
                    maybeLeakingParameter = true;
                    break;
                }
            }
            final LeakingParameters leakingParametersAndFrames = maybeLeakingParameter ? leakingParametersAndFrames(method, methodNode, argumentTypes, jsr) : null;
            boolean[] leakingParameters = leakingParametersAndFrames != null ? leakingParametersAndFrames.parameters : null;
            boolean[] leakingNullableParameters = leakingParametersAndFrames != null ? leakingParametersAndFrames.nullableParameters : null;
            final boolean[] origins = isInterestingResult ? OriginsAnalysis.resultOrigins(leakingParametersAndFrames.frames, methodNode.instructions, richControlFlow.controlFlow) : null;
            Equation outEquation = isInterestingResult ? new InOutAnalysis(richControlFlow, Out, origins, stable, sharedPendingStates).analyze() : null;
            if (isReferenceResult) {
                result.add(outEquation);
                result.add(new Equation(new Key(method, NullableOut, stable), NullableMethodAnalysis.analyze(methodNode, origins, jsr)));
            }
            boolean withCycle = !richControlFlow.dfsTree.back.isEmpty();
            if (argumentTypes.length > 50 && withCycle) {
                // IDEA-137443 - do not analyze very complex methods
                return;
            }
            // arguments and contract clauses
            for (int i = 0; i < argumentTypes.length; i++) {
                boolean notNullParam = false;
                if (ASMUtils.isReferenceType(argumentTypes[i])) {
                    boolean possibleNPE = false;
                    if (leakingParameters[i]) {
                        NonNullInAnalysis notNullInAnalysis = new NonNullInAnalysis(richControlFlow, new In(i, In.NOT_NULL_MASK), stable, sharedPendingActions, sharedResults);
                        Equation notNullParamEquation = notNullInAnalysis.analyze();
                        possibleNPE = notNullInAnalysis.possibleNPE;
                        notNullParam = notNullParamEquation.rhs.equals(FINAL_NOT_NULL);
                        result.add(notNullParamEquation);
                    } else {
                        // parameter is not leaking, so it is definitely NOT @NotNull
                        result.add(new Equation(new Key(method, new In(i, In.NOT_NULL_MASK), stable), FINAL_TOP));
                    }
                    if (leakingNullableParameters[i]) {
                        if (notNullParam || possibleNPE) {
                            result.add(new Equation(new Key(method, new In(i, In.NULLABLE_MASK), stable), FINAL_TOP));
                        } else {
                            result.add(new NullableInAnalysis(richControlFlow, new In(i, In.NULLABLE_MASK), stable, sharedPendingStates).analyze());
                        }
                    } else {
                        result.add(new Equation(new Key(method, new In(i, In.NULLABLE_MASK), stable), FINAL_NULL));
                    }
                    if (isInterestingResult) {
                        if (leakingParameters[i]) {
                            if (notNullParam) {
                                // @NotNull, so "null->fail"
                                result.add(new Equation(new Key(method, new InOut(i, Value.Null), stable), FINAL_BOT));
                            } else {
                                // may be null on some branch, running "null->..." analysis
                                if (isBooleanResult && negatedAnalysis != null) {
                                    result.add(negatedAnalysis.contractEquation(i, Value.Null, stable));
                                } else {
                                    result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.Null), origins, stable, sharedPendingStates).analyze());
                                }
                            }
                            if (isBooleanResult && negatedAnalysis != null) {
                                result.add(negatedAnalysis.contractEquation(i, Value.NotNull, stable));
                            } else {
                                result.add(new InOutAnalysis(richControlFlow, new InOut(i, Value.NotNull), origins, stable, sharedPendingStates).analyze());
                            }
                        } else {
                            // parameter is not leaking, so a contract is the same as for the whole method
                            result.add(new Equation(new Key(method, new InOut(i, Value.Null), stable), outEquation.rhs));
                            result.add(new Equation(new Key(method, new InOut(i, Value.NotNull), stable), outEquation.rhs));
                        }
                    }
                }
            }
        }

        private void processNonBranchingMethod(Method method, Type[] argumentTypes, ControlFlowGraph graph, boolean isReferenceResult, boolean isBooleanResult, boolean stable, List<Equation> result) throws AnalyzerException {
            CombinedAnalysis analyzer = new CombinedAnalysis(method, graph);
            analyzer.analyze();
            if (isReferenceResult) {
                result.add(analyzer.outContractEquation(stable));
                result.add(analyzer.nullableResultEquation(stable));
            }
            for (int i = 0; i < argumentTypes.length; i++) {
                Type argType = argumentTypes[i];
                if (ASMUtils.isReferenceType(argType)) {
                    result.add(analyzer.notNullParamEquation(i, stable));
                    result.add(analyzer.nullableParamEquation(i, stable));
                    if (isReferenceResult || isBooleanResult) {
                        result.add(analyzer.contractEquation(i, Value.Null, stable));
                        result.add(analyzer.contractEquation(i, Value.NotNull, stable));
                    }
                }
            }
        }

        private List<Equation> topEquations(Method method, Type[] argumentTypes, boolean isReferenceResult, boolean isInterestingResult, boolean stable) {
            // 4 = @NotNull parameter, @Nullable parameter, null -> ..., !null -> ...
            List<Equation> result = new ArrayList<>(argumentTypes.length * 4 + 2);
            if (isReferenceResult) {
                result.add(new Equation(new Key(method, Out, stable), FINAL_TOP));
                result.add(new Equation(new Key(method, NullableOut, stable), FINAL_BOT));
            }
            for (int i = 0; i < argumentTypes.length; i++) {
                if (ASMUtils.isReferenceType(argumentTypes[i])) {
                    result.add(new Equation(new Key(method, new In(i, In.NOT_NULL_MASK), stable), FINAL_TOP));
                    result.add(new Equation(new Key(method, new In(i, In.NULLABLE_MASK), stable), FINAL_TOP));
                    if (isInterestingResult) {
                        result.add(new Equation(new Key(method, new InOut(i, Value.Null), stable), FINAL_TOP));
                        result.add(new Equation(new Key(method, new InOut(i, Value.NotNull), stable), FINAL_TOP));
                    }
                }
            }
            return result;
        }

        @NotNull
        private LeakingParameters leakingParametersAndFrames(Method method, MethodNode methodNode, Type[] argumentTypes, boolean jsr) throws AnalyzerException {
            return argumentTypes.length < 32 ? LeakingParameters.buildFast(method.internalClassName, methodNode, jsr) : LeakingParameters.build(method.internalClassName, methodNode, jsr);
        }
    }, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
    return equations;
}
Also used : HashMap(java.util.HashMap) ContainerUtil(com.intellij.util.containers.ContainerUtil) NotNull(org.jetbrains.annotations.NotNull) MethodNode(org.jetbrains.org.objectweb.asm.tree.MethodNode) ArrayList(java.util.ArrayList) List(java.util.List) ProcessCanceledException(com.intellij.openapi.progress.ProcessCanceledException) AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException)

Example 4 with AnalyzerException

use of org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException in project intellij-community by JetBrains.

the class FramelessAnalyzer method analyze.

public void analyze(final MethodNode m) throws AnalyzerException {
    n = m.instructions.size();
    if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0 || n == 0) {
        return;
    }
    insns = m.instructions;
    handlers = (List<TryCatchBlockNode>[]) new List<?>[n];
    subroutines = new Subroutine[n];
    queued = new boolean[n];
    wasQueued = new boolean[n];
    queue = new int[n];
    top = 0;
    // computes exception handlers for each instruction
    for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
        TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
        int begin = insns.indexOf(tcb.start);
        int end = insns.indexOf(tcb.end);
        for (int j = begin; j < end; ++j) {
            List<TryCatchBlockNode> insnHandlers = handlers[j];
            if (insnHandlers == null) {
                insnHandlers = new ArrayList<>();
                handlers[j] = insnHandlers;
            }
            insnHandlers.add(tcb);
        }
    }
    // computes the subroutine for each instruction:
    Subroutine main = new Subroutine(null, m.maxLocals, null);
    List<AbstractInsnNode> subroutineCalls = new ArrayList<>();
    Map<LabelNode, Subroutine> subroutineHeads = new HashMap<>();
    findSubroutine(0, main, subroutineCalls);
    while (!subroutineCalls.isEmpty()) {
        JumpInsnNode jsr = (JumpInsnNode) subroutineCalls.remove(0);
        Subroutine sub = subroutineHeads.get(jsr.label);
        if (sub == null) {
            sub = new Subroutine(jsr.label, m.maxLocals, jsr);
            subroutineHeads.put(jsr.label, sub);
            findSubroutine(insns.indexOf(jsr.label), sub, subroutineCalls);
        } else {
            sub.callers.add(jsr);
        }
    }
    for (int i = 0; i < n; ++i) {
        if (subroutines[i] != null && subroutines[i].start == null) {
            subroutines[i] = null;
        }
    }
    merge(0, null);
    // control flow analysis
    while (top > 0) {
        int insn = queue[--top];
        Subroutine subroutine = subroutines[insn];
        queued[insn] = false;
        AbstractInsnNode insnNode = null;
        try {
            insnNode = m.instructions.get(insn);
            int insnOpcode = insnNode.getOpcode();
            int insnType = insnNode.getType();
            if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
                merge(insn + 1, subroutine);
                newControlFlowEdge(insn, insn + 1);
            } else {
                subroutine = subroutine == null ? null : subroutine.copy();
                if (insnNode instanceof JumpInsnNode) {
                    JumpInsnNode j = (JumpInsnNode) insnNode;
                    if (insnOpcode != GOTO && insnOpcode != JSR) {
                        merge(insn + 1, subroutine);
                        newControlFlowEdge(insn, insn + 1);
                    }
                    int jump = insns.indexOf(j.label);
                    if (insnOpcode == JSR) {
                        merge(jump, new Subroutine(j.label, m.maxLocals, j));
                    } else {
                        merge(jump, subroutine);
                    }
                    newControlFlowEdge(insn, jump);
                } else if (insnNode instanceof LookupSwitchInsnNode) {
                    LookupSwitchInsnNode lsi = (LookupSwitchInsnNode) insnNode;
                    int jump = insns.indexOf(lsi.dflt);
                    merge(jump, subroutine);
                    newControlFlowEdge(insn, jump);
                    for (int j = 0; j < lsi.labels.size(); ++j) {
                        LabelNode label = lsi.labels.get(j);
                        jump = insns.indexOf(label);
                        merge(jump, subroutine);
                        newControlFlowEdge(insn, jump);
                    }
                } else if (insnNode instanceof TableSwitchInsnNode) {
                    TableSwitchInsnNode tsi = (TableSwitchInsnNode) insnNode;
                    int jump = insns.indexOf(tsi.dflt);
                    merge(jump, subroutine);
                    newControlFlowEdge(insn, jump);
                    for (int j = 0; j < tsi.labels.size(); ++j) {
                        LabelNode label = tsi.labels.get(j);
                        jump = insns.indexOf(label);
                        merge(jump, subroutine);
                        newControlFlowEdge(insn, jump);
                    }
                } else if (insnOpcode == RET) {
                    if (subroutine == null) {
                        throw new AnalyzerException(insnNode, "RET instruction outside of a sub routine");
                    }
                    for (int i = 0; i < subroutine.callers.size(); ++i) {
                        JumpInsnNode caller = subroutine.callers.get(i);
                        int call = insns.indexOf(caller);
                        if (wasQueued[call]) {
                            merge(call + 1, subroutines[call], subroutine.access);
                            newControlFlowEdge(insn, call + 1);
                        }
                    }
                } else if (insnOpcode != ATHROW && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
                    if (subroutine != null) {
                        if (insnNode instanceof VarInsnNode) {
                            int var = ((VarInsnNode) insnNode).var;
                            subroutine.access[var] = true;
                            if (insnOpcode == LLOAD || insnOpcode == DLOAD || insnOpcode == LSTORE || insnOpcode == DSTORE) {
                                subroutine.access[var + 1] = true;
                            }
                        } else if (insnNode instanceof IincInsnNode) {
                            int var = ((IincInsnNode) insnNode).var;
                            subroutine.access[var] = true;
                        }
                    }
                    merge(insn + 1, subroutine);
                    newControlFlowEdge(insn, insn + 1);
                }
            }
            List<TryCatchBlockNode> insnHandlers = handlers[insn];
            if (insnHandlers != null) {
                for (TryCatchBlockNode tcb : insnHandlers) {
                    newControlFlowExceptionEdge(insn, tcb);
                    merge(insns.indexOf(tcb.handler), subroutine);
                }
            }
        } catch (AnalyzerException e) {
            throw new AnalyzerException(e.node, "Error at instruction " + insn + ": " + e.getMessage(), e);
        } catch (Exception e) {
            throw new AnalyzerException(insnNode, "Error at instruction " + insn + ": " + e.getMessage(), e);
        }
    }
}
Also used : AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException) List(java.util.List) ArrayList(java.util.ArrayList)

Example 5 with AnalyzerException

use of org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException in project kotlin by JetBrains.

the class CodegenTestCase method verifyWithAsm.

private static boolean verifyWithAsm(@NotNull OutputFile file, ClassLoader loader) {
    ClassNode classNode = new ClassNode();
    new ClassReader(file.asByteArray()).accept(classNode, 0);
    SimpleVerifier verifier = new SimpleVerifier();
    verifier.setClassLoader(loader);
    Analyzer<BasicValue> analyzer = new Analyzer<BasicValue>(verifier);
    boolean noErrors = true;
    for (MethodNode method : classNode.methods) {
        try {
            analyzer.analyze(classNode.name, method);
        } catch (Throwable e) {
            System.err.println(file.asText());
            System.err.println(classNode.name + "::" + method.name + method.desc);
            //noinspection InstanceofCatchParameter
            if (e instanceof AnalyzerException) {
                // Print the erroneous instruction
                TraceMethodVisitor tmv = new TraceMethodVisitor(new Textifier());
                ((AnalyzerException) e).node.accept(tmv);
                PrintWriter pw = new PrintWriter(System.err);
                tmv.p.print(pw);
                pw.flush();
            }
            e.printStackTrace();
            noErrors = false;
        }
    }
    return noErrors;
}
Also used : ClassNode(org.jetbrains.org.objectweb.asm.tree.ClassNode) AnalyzerException(org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException) SimpleVerifier(org.jetbrains.org.objectweb.asm.tree.analysis.SimpleVerifier) Analyzer(org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer) Textifier(org.jetbrains.org.objectweb.asm.util.Textifier) TraceMethodVisitor(org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor) BasicValue(org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue) MethodNode(org.jetbrains.org.objectweb.asm.tree.MethodNode) ClassReader(org.jetbrains.org.objectweb.asm.ClassReader) PrintWriter(java.io.PrintWriter)

Aggregations

AnalyzerException (org.jetbrains.org.objectweb.asm.tree.analysis.AnalyzerException)5 ArrayList (java.util.ArrayList)3 HashMap (java.util.HashMap)3 List (java.util.List)3 MethodNode (org.jetbrains.org.objectweb.asm.tree.MethodNode)3 ProcessCanceledException (com.intellij.openapi.progress.ProcessCanceledException)1 ContainerUtil (com.intellij.util.containers.ContainerUtil)1 PrintWriter (java.io.PrintWriter)1 Annotation (java.lang.annotation.Annotation)1 NotNull (org.jetbrains.annotations.NotNull)1 ClassReader (org.jetbrains.org.objectweb.asm.ClassReader)1 Type (org.jetbrains.org.objectweb.asm.Type)1 ClassNode (org.jetbrains.org.objectweb.asm.tree.ClassNode)1 Analyzer (org.jetbrains.org.objectweb.asm.tree.analysis.Analyzer)1 BasicValue (org.jetbrains.org.objectweb.asm.tree.analysis.BasicValue)1 Frame (org.jetbrains.org.objectweb.asm.tree.analysis.Frame)1 SimpleVerifier (org.jetbrains.org.objectweb.asm.tree.analysis.SimpleVerifier)1 Textifier (org.jetbrains.org.objectweb.asm.util.Textifier)1 TraceMethodVisitor (org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor)1