JDK-7127066 : Class verifier accepts an invalid class file
  • Type: Bug
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 7
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2012-01-04
  • Updated: 2015-09-29
  • Resolved: 2015-03-25
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 6 JDK 7 JDK 8 JDK 9
6u105Fixed 7u85Fixed 8u60Fixed 9 b64Fixed
Related Reports
Relates :  
Description
SYNOPSIS
--------
Class verifier accepts an invalid class file

OPERATING SYSTEM
----------------
All

FULL JDK VERSION
----------------
Java 7

PROBLEM DESCRIPTION
-------------------
A class file is attached to this bug report, which is actually invalid. However, the HotSpot VM class verifier does not detect the problem, and loads the class.

The class is invalid because the StackMap for bytecode index 45 is incorrect. The stack maps for bytecode indexes 45 and 49 are incompatible because 45 doesn't supply enough locals to satisfy 49:

    frame_type = 255 /* full_frame */
    offset_delta = 2    // bytecode index = 45
    locals = [ class java/lang/Object, class java/lang/Object ]
    stack = [ class java/lang/Exception ]

    frame_type = 255 /* full_frame */
    offset_delta = 3    // bytecode index = 49
    locals = [ class java/lang/Object, class java/lang/Object, class java/lang/Object ]
    stack = [ class java/lang/Throwable ]

Bytecode index 45 represents an exception handler that is only reachable if an exception occurs between index 37 and 42.  The StackMap for bytecode index 37 is:

    frame_type = 255 /* full_frame */
    offset_delta = 1    // bytecode index = 37
    locals = [ class java/lang/Object, class java/lang/Object, class java/lang/Object ]
    stack = []

If an exception occurs at bytecode index 37, 3 locals will be provided to index 45. Bytecode index 45 is, in turn, protected by a handler at index 49. If an exception occurs during the execution of the bytecode at index 45, the stack must be compatible with index 49. This is not the case here because it doesn't provide enough locals.

The issue should be exposed by the strict class file checking feature in Java 7:

    http://openjdk.java.net/projects/jdk7/features/#fa535991

One aspect of this feature is that correct StackMapTable attributes are mandatory for methods in Java 7. In earlier releases, the JVM is allowed to fallback to the old flow verification, so this isn't a problem on Java 6.

TESTCASE
--------
See attached file "BadMap.class".

REPRODUCTION INSTRUCTIONS
-------------------------
Simply run: java BadMap

Expected result:
A java.lang.VerifyError should be thrown, describing the problem.

Actual Result:
The class is loaded successfully.

WORKAROUND
----------
None

Comments
http://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.4 Stack map frames are represented in Prolog as a list of terms of the form: stackMap(Offset, TypeState) where: Offset is an integer indicating the bytecode offset at which the stack map frame applies (��4.7.4). The order of bytecode offsets in this list must be the same as in the class file. TypeState is the expected incoming type state for the instruction at Offset.
22-09-2014

The attached test case does not get a VerifyError when run with the old verifier.
28-08-2014

EVALUATION Cause known.
17-02-2012