Provide additional contextual information about bytecode-verification errors to
ease diagnosis of bytecode or stackmap deficiencies in the field.
Bytecodes are verified by the JVM's bytecode verifier. Bytecodes emitted
by the JDK's `javac` compiler generally result in highly conformant bytecode.
However, there are other tools and packages that modify bytecode for
various reasons, including instrumentation and debugging. Occasionally,
post-processing bytecode results in a `VerifyError`. Currently, the message
associated with the error is rather terse and non-specific. The purpose
of this feature is to expand the information available when a `VerifyError`
occurs in modern classfiles so that a developer can more quickly resolve the
While additional data about errors can be provided, it is not the goal to
provide "all possible" data about an error, especially in cases where
additional data can be obtained by other means. For instance, while
the actual bytecode where the problem occurs may be included in an error
message, it may not be disassembled into human-readable form. Additionally
the state of the system such as loaded classes and their relationships are
not provided as this information is available using other mechanisms.
This extra data will only be available and displayed for errors that are
generated by the type-checking verifier. Classfiles with a version less
than 50 are verified using the inferencing verifier. Errors generated by
the inferencing verifier will not change.
The format of the error message and it's data are not official nor fully
specified, and are subject to change in any release.
This project is considered successful if the additional data provided is
used by any single engineer to diagnose a real verification error situation.
Given the unpredictability of the problem, and the continuing resistance of
engineers to allow implanted tracking chips in their brains, there really
is no useful metric that can be applied in this case. We have to rely upon
common sense and experience in determining what is likely to be useful, which
is historically a notoriously hard thing to quantify.
Verification errors are hard to decipher. The current messages attached to
VerifyError messages are cryptic and provide very little help in pinpointing
where and why the bytecode or stackmap is flawed.
There are two parts to this project. The first is the exposure of a previously
internal flag which traces the verification project, and the second an
augmentation of the messages contained in a VerifyError with additional
The flag which turns on verification tracing was previously an internal
global flag which required a change to the source and a recompile of the JVM
(in debug mode) to enable. This project turns that flag into the diagnostic
flag, 'VerboseVerification'. As such, verification tracing can be turned on
(even in product mode) using the command-line flags:
When run with this flag enabled, the JVM will output tracing information to
stdout. This tracing information details which methods are being verified,
what mechanism is used for verification, the method's stackmap table. and in
debug mode, each instruction's bci, opcode, and current frame state.
In addition, the traditional error message included in thrown VerifyError
instance is augmented with the following detailed information: the exact
location where the error was detected (class and method name plus
bytecode offset); a more detailed error notification which details the origins
of any referenced types (if applicable); the current analysis frame state
(if applicable); a hex dump of the bytecode; a textual representation of the
exception handler table; a textual representation of the stack map table.
The additional error details are formatted into sections and present in a
multi-line format in the exception message. The original error message is
also unchanged and present at the beginning of the exception message.
One alternative is to not augment with detailed error messages unless a
command-line flag is present. This is still a possibility, but since
VerifyErrors are rare it is assumed that having extra details by default
will not cause any problems.
Existing test suites for the bytecode verifier can be used to validate
this feature. Some tests however, might need to be enhanced to expect
additional diagnostic information provided by this feature.
Comprehensive testing requires crafting a number of tests (each being a
specialized classfile) which triggers a VerifyError in each possible place
in the code, as well as creating a variety of tests that exercise the
different origins for types (stack/locals/constant pool).
Risks and Assumptions
Very low risk. We do assume that no one is dependent on the existing
contents of the VerifyError exception message and thus it is safe for
us to augment it without compatibility problems. If this assumption is
wrong we may want to investigate the listed alternative.
We expect no impact upon other parts of the platform.