How safe is it to use -XX:-UseSplitVerifier?
Asked Answered
E

3

48

There are known compatibility issues with JDK7 compiled code using instrumentation. As for http://www.oracle.com/technetwork/java/javase/compatibility-417013.html

Classfiles with version number 51 are exclusively verified using the type-checking verifier, and thus the methods must have StackMapTable attributes when appropriate. For classfiles with version 50, the Hotspot JVM would (and continues to) failover to the type-inferencing verifier if the stackmaps in the file were missing or incorrect. This failover behavior does not occur for classfiles with version 51 (the default version for Java SE 7). Any tool that modifies bytecode in a version 51 classfile must be sure to update the stackmap information to be consistent with the bytecode in order to pass verification.

The solution is to use -XX:-UseSplitVerifier as summarised here: https://community.oracle.com/blogs/fabriziogiudici/2012/05/07/understanding-subtle-new-behaviours-jdk-7

How safe it is? I suppose Oracle has put this check in for a reason. If I don't use it, I may be risking some other issues.

What can be consequences of using -XX:-UseSplitVerifier?

Thanks,

Piotr.

Ensiform answered 6/3, 2013 at 16:46 Comment(1)
As an extension and possible consequence for future readers, but in Java8 that flag is deprecated. Read this for details.Arruda
S
54

In short, it's perfectly safe.

Since Java 6, Oracle's compiler has made class files with a StackMapTable. The basic idea is that the compiler can explicitly specify what the type of an object is, instead of making the runtime do it. That provides a tiny speedup in the runtime, in exchange for some extra time during compile and some complexity in the compiled class file (the aforementioned StackMapTable).

As an experimental feature, it was not enabled by default in the Java 6 compiler. The runtime defaults to verifying the object types itself if no StackMapTable exists.

Until Java 7. Oracle made it mandatory: the compiler generates them, and the runtime verifies them. It still uses the old verifier if the StackMapTable isn't there... but only on class files from Java 6 or earlier (version 50). Java 7 class files (version 51) are required to use the StackMapTable, and so the runtime won't cut them the same slack.

That's only a problem if your classfiles were generated without a StackMapTable. For instance, if you used a non-Oracle JVM. Or if you messed with bytecode afterwards -- like instrumenting it for use with a debugger, optimizer, or code coverage analyzer.

But you can get around it! Oracle's JVM provides the -XX:+UseSplitVerifier to force the runtime to fallback to the old type verifier. It doesn't care about StackMapTable.

In practice, the hoped-for optimization in runtime speed and efficiency hasn't materialized: if it exists, it hasn't been enough for anyone to notice. As the new type verifier doesn't provide any new features (just the optimization), it's perfectly safe to shut it off.

Oracle's explanation is at http://www.oracle.com/technetwork/java/javase/compatibility-417013.html if you search for JSR 202.

Saad answered 9/5, 2013 at 16:56 Comment(2)
Yes, the StackMapTable was a total botch job on Sun's part. Among other things, they could have greatly improved the speed of the old verifier if they'd only tried (or asked me).Reportorial
Minor nitpick, it's -XX:-UseSplitVerifier not -XX:+UseSplitVerifier. But I guess it doesn't matter now since it was removed in Java 8 anyway.Slumberland
A
24

Yes -- it's safe. As Judebert says, it just slows class loading slightly.

To add a little more info: What exactly is a StackMap Table? Well, the Bytecode verifier needs to make two passes over the code in the class file to validate proper types of data are being passed around and used. The first pass, which is the slower one, does flow analysis of all the code's branches to see what type of data could be on the stack at each bytecode instruction. The second pass looks at each instruction to see if it can validly operate on all those types.

Here's the key: the compiler already has all the information at hand that the first pass generates - so (in Java 6 & 7) it stores it in a StackMap table in the class file.

This speeds up class loading because the class loader doesn't have to do that first pass. That's why it's called a Split Verifier, because the work is split between the compiler and the runtime loading mechanism. When you use the -XX:-UseSplitVerifier option, you tell Java to do both passes at class load time (and to ignore any StackMap table). Many products (like profilers that modify bytecode at load time) did not know about the StackMap table initially, so when they modified classes at load time, the StackMap table from the compiler was out of date and caused errors.

SO, to summarize, the -XX:-UseSplitVerifier option slows class loading. It does not affect security, runtime performance or functionality.

Assist answered 15/10, 2013 at 14:13 Comment(2)
+1 For explaining the grounds of StackMap Table. From all the googled pages for StackMap table this is the easiest,exact and clear explaination I found.Archivist
It’s not just that the verifier has to do two passes. That first step may imply an arbitrary number of passes over the same code when it comes to (possibly nested) loops and/or (possibly nested) exception handlers as the same code might get executed with different prerequisites then and the verifier has to find out what is common.This might also imply searching the class and interface hierarchy for the most specific common base type(s) for two or more types.Tisiphone
A
13

Stack Map Frames were added in Java 7 and "prashant" argues that the idea is flawed and proposes that developers always use the -XX:-UseSplitVerifier flag to avoid using them.

Read more: Java 7 Bytecode Verifier: Huge backward step for the JVM

Aerobiology answered 26/3, 2013 at 13:14 Comment(2)
So does this mean that the verifier is not running in Java 7? Or that only parts of it are executed, and others (like the article says) are now supposed to be managed by the compiler?Iene
@DinisCruz The verifier always runs. Using -XX:-UseSplitVerifier tells the jvm to use the 2 pass method, which is slightly slower than the new default -- which runs just the second pass that references the StackMap Table data. In other words, the first pass is always run by the compiler -- and either the runtime does the first pass again, or it uses the intermediate results stored in the StackMap table by the compiler.Assist

© 2022 - 2024 — McMap. All rights reserved.