java - 在字节码中确定 super() 方法调用的位置是所有构造函数必须在 JVM 上执行的操作

标签 java bytecode

我想知道在分析构造函数的字节码时是否有一种明显且快速的方法来确定 super() 在哪里代码结束于。

更具体地说,与 Java 形成鲜明对比的是,Java 在构造函数中调用任何 super()。构造函数方法是可选的(或者更确切地说,当不存在时——隐式),在字节码世界中它总是需要的。

出于黑魔法的目的,我需要通过字节码分析和最简单的可用方法来了解 INVOKESPECIAL 是什么对应于 Java 世界的 super() 的调用打电话。

我会留给你一个很难的例子:

public static class A {
    public A(Object o, Object b) {
    }
}

public static class B extends A {
    public B() {
        //the below super is in bold just to signal that's the one
        //I'm looking for
        SUPER(new A(new Object(), new Integer(2)), new Integer(1));
        System.out.println(new A(new Object(), new Integer(2)));
    }
}

对应的字节码: enter image description here

最佳答案

实际上,字节码构造函数的规则比 Java 的规则宽松得多。

唯一的规则是必须在任何正常返回的路径上调用恰好一个构造函数,如果构造函数调用抛出异常,那么您也必须抛出异常。

除其他外,这意味着构造函数可能包含对其他构造函数的多次调用或根本不调用。

无论如何,确定给定的 invokespecial 调用是否正在初始化当前对象的唯一有保证的方法是进行数据流分析,因为有可能初始化同一类的其他对象,这会造成混淆一个朴素的检测器。

编辑:这是一个完全有效的类示例(使用 Krakatau 汇编程序语法),显示了您可能会遇到的一些问题。除其他外,它具有调用同一类中的其他构造函数、构造函数的递归调用以及在构造函数内部构造同一类的其他对象。

.class public ctors
.super java/lang/Object

; A normal constructor
.method public <init> : ()V
    .limit locals 1
    .limit stack 1

    aload_0
    invokespecial java/lang/Object <init> ()V
    return
.end method

; A weird constructor
.method public <init> : (I)V
    .limit locals 2
    .limit stack 5

    iload_1
    ifne LREST
        aload_0
        invokespecial ctors <init> ()V
        return

LREST:
    aload_0
    new ctors
    iinc 1 -1
    iload_1
LFAKE_START:
    invokespecial ctors <init> (I)V
LFAKE_END:
    iconst_0
    invokespecial ctors <init> (I)V
    return

.catch [0] from LFAKE_START to LFAKE_END using LCATCH
LCATCH:
    aload_0
    invokespecial java/lang/Object <init> ()V
    return
.end method

.method public static main : ([Ljava/lang/String;)V
    .limit locals 1
    .limit stack 2

    new ctors
    iconst_5
    invokespecial ctors <init> (I)V
    return
.end method

关于java - 在字节码中确定 super() 方法调用的位置是所有构造函数必须在 JVM 上执行的操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14633109/

相关文章:

java - Swing 自定义边框

java - 与 Socket 关联的流

java - ASM Tree API 插入 InsnList 会出现 StackOverflowError?

java - 将未导出/未打开的包添加到模块信息的 ModulePackages 的用例是什么?

java - JDK 中的非常规代码 - 用于未知原因的特定结构

java - 识别Java字节码中的循环

java - POI 4.1.0 折线图 y 系列显示错误的图例

Java 打印基于位置

java - 为什么消费者会降低生产者的绩效

java - 使用 Javassist 编辑 JFrame 类时出现 IllegalAccessError