62

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?

3
  • 4
    Interesting question - but why would you want to be able to throw a non-throwable? (Is it just to open a bug?) Commented Apr 21, 2011 at 21:25
  • @RonK It's mostly curiosity; I want to know what's the reason why Java forces us to throw objects with a larger footprint than they could be. Note I don't intend to use this in real code. Commented Apr 21, 2011 at 21:34
  • @RonK: Valid usecases include designing a new java dialect, or a new JVM language. Commented Aug 15, 2016 at 11:32

3 Answers 3

74

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.

Sign up to request clarification or add additional context in comments.

Comments

8

As mentioned in John's answer, you can disable verification (placing the class on the bootclasspath should also work ), load and execute a class throwing a non-Throwable class successfully.

Surprisingly, it doesn't necessarily lead to a crash!

As long as you don't call Throwable methods implicitly or explicitly, everything will work perfectly fine:

.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 

Result:

% java -Xverify:none ThrowObject Thrown and catched Object successfully! 

Comments

5

[...] disable the bytecode verifier [...]

The bytecode verification is part of the JVM spec, so if you disable this (or tamper with the JVM in other ways), you can, depending on implementation, do just about anything (including throwing primitives etc) I would assume.

Quote from the JVM specification:

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.

I.e., your question can be interpreted as "If a JVM deviates from the specification, can it do weird stuff such as throwing primitivs" and the answer is of course, yes.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.