代码之家  ›  专栏  ›  技术社区  ›  Manos Ntoulias

使用旧语义调用:调用其他类的实例方法

  •  0
  • Manos Ntoulias  · 技术社区  · 5 年前

    根据 this 在旧的Java版本中,有一个不受限制的版本,叫做NoWoNoNoVIN。此指令允许您在不进行虚拟查找的情况下调用实例方法,如果我获得了这一权利,那么这些方法可能属于当前方法的不可赋值类。使用InvokeSpecial时,由于它仅用于调用super、private或initializing方法,因此发生了更改。

    我的问题是:有没有办法用Java 8(或更高)绕过那些结构约束? [4.9.2] 对invokeSpecial指令和不进行虚拟查找的调用,使用不同类(即与当前类不兼容的赋值类)的方法。

    我可以使用no-verify标志来禁用验证过程,但是有更优雅的方法吗?

    1 回复  |  直到 5 年前
        1
  •  3
  •   Antimony    5 年前

    你把两个不同的问题混为一谈。 invokenonvirtual inokespecial 都是一样的,一直都是。对于同一操作码,它们只是两个不同的名称。

    你链接的问题是关于一个单独的功能 ACC_SUPER 有着悠久而复杂的历史。

    基本上,在非常早期的Java版本中,超级调用的编译被打破了。在编译超类调用时,它将插入 invokespecial 到超类方法 编制时 . 如果随后更改了类层次结构,则即使在层次结构的中间点插入了新的重写,它仍将尝试调用它编译为调用的方法。

    注意,这仍然不允许您在不相关的类中调用方法——这个问题只与编译后在同一继承中添加的同一方法的不同重写有关。

    在Java作者意识到他们的错误之后,他们更新了JVM的处理方法。 不寻常的 正确处理超级电话。现在,无论指令中指定了哪个方法,它都将在链接/运行时遍历超类层次结构并调用适当的方法。

    但是,他们担心旧版本的Java编译的代码依赖于被破坏的行为,因此为了向后兼容,他们添加了一个新的CaseFrand标志, 超级电容器 . 如果在类上设置了标志,则它具有新的(正确的)行为;如果没有,则使用旧的行为。因为旧的类文件是在标志存在之前编译的,所以它们不会设置它。同时,编译器被更新为 超级电容器 在所有的新课上,每个人都很开心…

    直到2011年。结果是 java.lang.Thread 具有用户不应该调用的安全敏感方法。防止人们从 Thread 他们超越了它,抛出了一个例外。然而, someone realized 黑客可以定义 螺纹 没有 超级电容器 标志,因此跳过安全检查并调用该方法的危险版本,并从Java沙箱中退出。

    不幸的是,修复此安全漏洞的唯一方法是删除 超级电容器 完全的特性——即将每个类视为已经设置了标志,不管它是否真的设置了标志。它被快速固定在Java 7更新13中,并且在Java 8中,规范本身被更改为文档。 超级电容器 不再有任何影响。

    所以答案是否定的,在7U13之后,没有任何方法可以获得Java版本中的超级调用的旧行为,或者是任何实现安全修复的更新。