JDK-8228604 : StackMapFrames are missing from redefined class bytes of retransformed classes
  • Type: Bug
  • Component: hotspot
  • Sub-Component: jvmti
  • Affected Version: 8,11.0.5,21
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: generic
  • CPU: generic
  • Submitted: 2019-07-22
  • Updated: 2023-01-12
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 21
21Unresolved
Related Reports
Duplicate :  
Description
ADDITIONAL SYSTEM INFORMATION :
Reproduced with the latest Java SE versions, 11.0.4 and 8u221, on Ubuntu 16.04.

A DESCRIPTION OF THE PROBLEM :
When retransforming a class via JVMTI RetransformClasses, and registering to the ClassFileLoadHook, the original class bytes passed in the classBeingRedefined pointer parameter are missing the StackMapFrame attributes of all methods.

As a result, when such class is instrumented using ASM, even if no bytes are actually changed, it is likely to crash the JVM. This was originally described in ASM issue 317876: https://gitlab.ow2.org/asm/asm/issues/317876.

For Java 7+ classes, ASM relies on classes always having a StackMapTable, and attempts to calculate max stack depth and the number of locals using the available StackMaps. When StackMapTable is missing, the max stack is wrongly calculated for the method, resulting in a too small value. Then, when this class is collected during GC, class verification fails (during OopMaps calculation) with the message "fatal error: Illegal class file encountered. Try running with -Xverify:all in method loadProvider", and a hs_err.log will be generated.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
The issue could be reproduced with the following reproducer:

https://github.com/shaharv/jvm/releases/download/v0.1.asm-317876/jvm-redefined-bytes-missing-stackmaptable.tar.gz

It consists of a simple JVMTI agent, short java test and test scripts.
For running the example, extract and ./run.sh.

The example code is also available in:
https://github.com/shaharv/jvm/tree/master/jvmti/asm-317876

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The class bytes of redefined and plainly loaded classes both contain StackMapTables.

The good test output should be as follows:

```
+ javap -p -l -v -s -c out/java_util_Date_loaded.class
+ javap -p -l -v -s -c out/java_util_Date_redefined.class
+ grep 'StackMapTable: number_of_entries' out/java_util_Date_loaded.class.disasm.txt
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 53
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 4
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 5
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 1
+ set +e
++ grep 'StackMapTable: number_of_entries' out/java_util_Date_redefined.class.disasm.txt
+ FOUND_STACKMAP='      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 53
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 4
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 5
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 1'
+ set -e
+ '[' -z '      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 53
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 4
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 5
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 1' ']'
+ echo 'Test passed.'
Test passed.
```
ACTUAL -
StackMapTables are missing from the redefined bytes.

The test output is:

```
+ /usr/lib/jvm/jdk-11.0.4/bin/javap -p -l -v -s -c out/java_util_Date_loaded.class
+ /usr/lib/jvm/jdk-11.0.4/bin/javap -p -l -v -s -c out/java_util_Date_redefined.class
+ grep 'StackMapTable: number_of_entries' out/java_util_Date_loaded.class.disasm.txt
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 53
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 4
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 3
      StackMapTable: number_of_entries = 5
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 2
      StackMapTable: number_of_entries = 1
      StackMapTable: number_of_entries = 1
+ set +e
++ grep 'StackMapTable: number_of_entries' out/java_util_Date_redefined.class.disasm.txt
+ FOUND_STACKMAP=
+ set -e
+ '[' -z '' ']'
+ echo 'Test failed: StackMapTable not found in redefined bytes.'
Test failed: StackMapTable not found in redefined bytes.
```

FREQUENCY : always



Comments
The issue is not resolved, it's reproducible in jdk 21 with java.lang.ProcessBuilder class
12-01-2023

Moving to JDK, we don't have plan to fix this issue in jdk8/jdk11 considering it has already fixed in higher versions.
25-07-2019

This issue is reproducible in 8u221/11.0.4 but not on the 12,13 and 14. 8u221 - Fail 11.0.4 - Fail 12 ea b14 - Fail 12 ea b15 - Pass <== Issue resolved here. 12 GA - Pass 13 GA - Pass 14 ea b04 - Pass Not able to find the exact duplicate issue.
24-07-2019