Conventional wisdom says you can only throw objects that extend Throwable
in Java, but is it possible to disable the bytecode verifier and get Java to compile and run code that throws arbitrary objects - or even primitives?
I looked up the JVM's athrow
and it will pop the first objref on the operand stack; but would it check if said reference points to a Throwable
at run time?
It depends on your JVM implementation. According to the Java VM specification it is undefined behavior if the object is not Throwable
.
The objectref must be of type reference and must refer to an object that is an instance of class Throwable or of a subclass of Throwable.
In section 6.1, "The Meaning of 'Must'":
If some constraint (a "must" or "must not") in an instruction description is not satisfied at run time, the behavior of the Java virtual machine is undefined.
I wrote a test program using the Jasmin assembler which does the equivalent of throw new Object()
. The Java HotSpot Server VM throws a 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
Disabling the bytecode verifier allows the athrow
to execute and the JVM appears to crash when it tries to print the exception's details. Compare these two programs, the first which throws an Exception
, the second which is the above test program which throws an Object
. Notice how it exits in the middle of a printout:
# 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" #
Of course, disabling the bytecode verifier is dangerous. The VM proper is written to assume that bytecode verification has been performed and therefore does not have to typecheck instruction operands. Beware: the undefined behavior that you invoke when you circumvent bytecode verification is much like the undefined behavior in C programs; anything at all can happen, including demons flying out of your nose.