你能在Java中加入什么?
传统观点认为,您只能抛出在Java中扩展的对象,但是是否有可能禁用字节码验证器并让Java编译和运行抛出任意对象(甚至是基元)的代码?Throwable
我查找了JVM的抛出
,它将弹出操作数堆栈上的第一个objref;但是它会检查所述引用是否在运行时指向 a?Throwable
传统观点认为,您只能抛出在Java中扩展的对象,但是是否有可能禁用字节码验证器并让Java编译和运行抛出任意对象(甚至是基元)的代码?Throwable
我查找了JVM的抛出
,它将弹出操作数堆栈上的第一个objref;但是它会检查所述引用是否在运行时指向 a?Throwable
这取决于您的 JVM 实现。根据 Java VM 规范,如果对象不是 ,则为未定义的行为。Throwable
objectref 必须是引用类型,并且必须引用作为类 Throwable 或 Throwable 子类的实例的对象。
如果在运行时不满足指令描述中的某些约束(“必须”或“不得”),则 Java 虚拟机的行为未定义。
我使用Jasmin汇编程序编写了一个测试程序,它相当于.Java HotSpot Server VM 抛出一个 :throw new Object()
VerifyError
# cat Athrow.j
.source Athrow.j
.class public Athrow
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 2
new java/lang/Object
dup
invokenonvirtual java/lang/Object/<init>()V
athrow
return
.end method
# java -jar jasmin.jar Athrow.j
Generated: Athrow.class
# java Athrow
Exception in thread "main" java.lang.VerifyError: (class: Athrow, method: main signature: ([Ljava/lang/String;)V) Can only throw Throwable objects
禁用字节码验证器允许执行,并且 JVM 在尝试打印异常的详细信息时似乎崩溃。比较这两个程序,第一个程序抛出一个,第二个是上面的测试程序,它抛出一个.请注意它在打印输出过程中是如何退出的:athrow
Exception
Object
# java -Xverify:none examples/Uncaught
Exception in thread "main" java.lang.Exception
at examples.Uncaught.main(Uncaught.j)
# java -Xverify:none Athrow
Exception in thread "main" #
当然,禁用字节码验证器是危险的。编写 VM 本身以假定已执行字节码验证,因此不必对指令操作数进行类型检查。请注意:在规避字节码验证时调用的未定义行为与C程序中的未定义行为非常相似;任何事情都可能发生,包括从你的鼻子里飞出来的恶魔。
正如 John 的回答中提到的,您可以禁用验证(将类放在 bootclasspath 上也应该有效),加载并成功执行抛出非类的类。Throwable
令人惊讶的是,它不一定会导致崩溃!
只要您不隐式或显式调用方法,一切都会正常工作:Throwable
.source ThrowObject.j
.class public ThrowObject
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
new java/lang/Object
dup
invokenonvirtual java/lang/Object/<init>()V
BeforeThrow:
athrow
AfterThrow:
return
CatchThrow:
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Thrown and catched Object successfully!"
invokevirtual java/io/PrintStream.println(Ljava/lang/String;)V
return
.catch all from BeforeThrow to AfterThrow using CatchThrow
.end method
结果:
% java -Xverify:none ThrowObject
Thrown and catched Object successfully!