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?
In Java, exceptions are objects. When you throw an exception, you throw an object. You can't throw just any object as an exception, however, only objects whose class descends from Throwable . Throwable serves as the base class for an entire family of classes, declared in java.
We can throw either checked or unchecked exception. The throw keyword is mainly used to throw custom exceptions.
You can only throw something that implements Throwable. So no, you can't throw a String . You would have to make something that implements throwable, then throw it. Probably better to have it implement exception though and have your exception message be the String.
The throw keyword is used to create a custom error. The throw statement is used together with an exception type. There are many exception types available in Java: ArithmeticException , ClassNotFoundException , ArrayIndexOutOfBoundsException , SecurityException , etc.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With