Using ClassWriter with COMPUTE_MAXS may generate non-valid frames
Expected Behavior
When performing code injection using COMPUTE_MAXS correct frames should be generated.
Current Behavior
Non-valid frames may be generated.
Steps to Reproduce
See the attached projects and test class "com.ibm.l3.util.VerifyClass".
Short Description: Using ClassWriter with COMPUTE_MAXS may generate non-valid frames.
Long Description:
When performing dynamic trace injection using ClassWriter and using flag COMPUTE_MAXS, non-valid frames may be generated. Attempting to load a class with non-valid frames fails with a VerifyError.
The problem is visible comparing byte codes generated using COMPUTE_MAXS with byte codes generated using COMPUTE_FRAMES.
The problem occurs using both v9.3 and v9.4 of ASM (using current published versions on Maven Central).
This non-valid frame was analyzed in detail by the IBM Java L3 support, with the following being the main comment:
So this means that the VerifyError is correct. The problem is the mismatch between the boolean type found in locals[1] at offset 42, vs the 'top' type specified in the stackmap table, i.e.:
locals = [ class com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager, 'top' ] (locals[0] = 0xc0, locals[1] = 0x1)
The JVM expected the stackmap entry to look something like this:
locals = [ class com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager, '[Z' ] (locals[0] = 0xc0, locals[1] = 0x1002)
See the attached archive for a test program which demonstrates the problem. The archive contains three Eclipse projects, "ASM 9.3", "ASM 9.4", and "TraceInjection".
Test class "com.ibm.l3.util.VerifyClass" in project "TraceInjection" reproduces the problem.
The test may be varied in two independent ways:
- By changing between COMPUTE_MAX and COMPUTE_FRAMES.
- By changing between ASM 9.3 and ASM 9.4.
The COMPUTE flag is updated at line 269 of "LibertyRuntimeTransformer.transform":
ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_MAXS);
// ClassWriter writer = new ClassWriter(reader, ClassWriter.COMPUTE_FRAMES);
The test class performs the following functions:
- Loads the initial byte codes for the class "ZosAssetFactoryManager". These are loaded from "initial/ZosAssetFactoryManager.class".
- Loads the byte codes for the (non-valid) COMPUTE_MAXS generated byte codes. These are loaded from "final/ZosAssetFactoryManager.class".
- Transforms the initial bytes using the Liberty dynamic trace injection, using API com.ibm.ws.ras.instrument.internal.main.LibertyRuntimeTransformer.transform.
- Runs all three versions of the byte codes through the ASM class verifier, which includes the display of the byte codes.
- Does a test load of the byte codes. (Note: In the Eclipse Environment, the Verify error does not occur.)
- Does a comparison of the "final" byte codes with the freshly instrumented byte codes. When COMPUTE_MAXS is set, the freshly instrumented byte codes match the "final" byte codes. When COMPUTE_FRAMES is set, the byte codes do not match.
The project includes Liberty source obtained from the Open Liberty GIT repository: https://github.com/OpenLiberty/open-liberty. The source is current as of 09-Nov-2022.
The project includes source for ASM 9.3 and ASM 9.4, obtained from Maven Central: https://search.maven.org/search?q=org.ow2.asm.
The non-valid frames cause class loading to throw a VerifyError:
ERROR ] TRAS3000E: Runtime injection of detailed method trace failed for class com.ibm.zosconnect.engine.impl.ZosAssetFactoryManager with exception java.lang.reflect.UndeclaredThrowableException at com.sun.proxy.$Proxy0.retransformClasses(Unknown Source) at com.ibm.ws.ras.instrument.internal.main.LibertyRuntimeTransformer.retransformClass(LibertyRuntimeTransformer.java:250) at [internal classes] at com.ibm.zosconnect.engine.impl.ZosAssetFactoryManager.(ZosAssetFactoryManager.java:28) at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:83) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:57) at java.lang.reflect.Constructor.newInstance(Constructor.java:437) at org.apache.felix.scr.impl.inject.internal.ComponentConstructorImpl.newInstance(ComponentConstructorImpl.java:312) at [internal classes] Caused by: java.lang.reflect.InvocationTargetException ... 16 more Caused by: java.lang.VerifyError ... 18 more
Byte code listings. The error is present at line 00017 of the byte codes which were generated using COMPUTE_MAXS.
Initial:
<init>()V
00000 ZosAssetFactoryManager . : : INVOKESTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.$jacocoInit ()[Z
00001 ZosAssetFactoryManager . : [Z : ASTORE 1
00002 ZosAssetFactoryManager [Z : : ALOAD 0
00003 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : INVOKESPECIAL java/lang/Object.<init> ()V
// TRACE INJECTION POINT
00004 ZosAssetFactoryManager [Z : : ALOAD 1
00005 ZosAssetFactoryManager [Z : [Z : ICONST_0
00006 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00007 ZosAssetFactoryManager [Z : [Z I I : BASTORE
00008 ZosAssetFactoryManager [Z : : ALOAD 0
00009 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : NEW java/util/HashMap
00010 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : DUP
00011 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap HashMap : INVOKESPECIAL java/util/HashMap.<init> ()V
00012 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : PUTFIELD com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.assetFactories : Ljava/util/Map;
00013 ZosAssetFactoryManager [Z : : ALOAD 1
00014 ZosAssetFactoryManager [Z : [Z : ICONST_1
00015 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00016 ZosAssetFactoryManager [Z : [Z I I : BASTORE
// TRACE INJECTION POINT
00017 ZosAssetFactoryManager [Z : : RETURN
Using COMPUTE_MAXS:
<init>()V
00000 ZosAssetFactoryManager . : : INVOKESTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.$jacocoInit ()[Z
00001 ZosAssetFactoryManager . : [Z : ASTORE 1
00002 ZosAssetFactoryManager [Z : : ALOAD 0
00003 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : INVOKESPECIAL java/lang/Object.<init> ()V
// BEGIN INJECTED TRACE
00004 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00005 ZosAssetFactoryManager [Z : I : IFEQ L0
00006 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00007 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L0
00008 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00009 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00010 ZosAssetFactoryManager [Z : I : IFEQ L0
00011 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00012 ZosAssetFactoryManager [Z : TraceComponent : LDC "<init>"
00013 ZosAssetFactoryManager [Z : TraceComponent String : LDC 0
00014 ZosAssetFactoryManager [Z : TraceComponent String I : ANEWARRAY java/lang/Object
00015 ZosAssetFactoryManager [Z : TraceComponent String [Object : INVOKESTATIC com/ibm/websphere/ras/Tr.entry (Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;[Ljava/lang/Object;)V
00016 ZosAssetFactoryManager [Z : : L0
00017 ZosAssetFactoryManager [Z : : FRAME FULL [com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager] [] // ***** NON-VALID *****
00018 ZosAssetFactoryManager [Z : : NOP
// END INJECTED TRACE
00019 ZosAssetFactoryManager [Z : : ALOAD 1
00020 ZosAssetFactoryManager [Z : [Z : ICONST_0
00021 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00022 ZosAssetFactoryManager [Z : [Z I I : BASTORE
00023 ZosAssetFactoryManager [Z : : ALOAD 0
00024 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : NEW java/util/HashMap
00025 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : DUP
00026 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap HashMap : INVOKESPECIAL java/util/HashMap.<init> ()V
00027 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : PUTFIELD com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.assetFactories : Ljava/util/Map;
00028 ZosAssetFactoryManager [Z : : ALOAD 1
00029 ZosAssetFactoryManager [Z : [Z : ICONST_1
00030 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00031 ZosAssetFactoryManager [Z : [Z I I : BASTORE
// BEGIN INJECTED TRACE
00032 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00033 ZosAssetFactoryManager [Z : I : IFEQ L1
00034 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00035 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L1
00036 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00037 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00038 ZosAssetFactoryManager [Z : I : IFEQ L1
00039 ZosAssetFactoryManager [Z : : ALOAD 0
00040 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : ALOAD 0
00041 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : SWAP
00042 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00043 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager TraceComponent : SWAP
00044 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager : LDC "<init>"
00045 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager String : SWAP
00046 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent String ZosAssetFactoryManager : INVOKESTATIC com/ibm/websphere/ras/Tr.exit (Ljava/lang/Object;Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;Ljava/lang/Object;)V
00047 ZosAssetFactoryManager [Z : : L1
00048 ZosAssetFactoryManager [Z : : FRAME SAME
// END INJECTED TRACE
00049 ZosAssetFactoryManager [Z : : RETURN
Using COMPUTE_FRAMES:
<init>()V
00000 ZosAssetFactoryManager . : : INVOKESTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.$jacocoInit ()[Z
00001 ZosAssetFactoryManager . : [Z : ASTORE 1
00002 ZosAssetFactoryManager [Z : : ALOAD 0
00003 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : INVOKESPECIAL java/lang/Object.<init> ()V
// BEGIN INJECTED TRACE
00004 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00005 ZosAssetFactoryManager [Z : I : IFEQ L0
00006 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00007 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L0
00008 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00009 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00010 ZosAssetFactoryManager [Z : I : IFEQ L0
00011 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00012 ZosAssetFactoryManager [Z : TraceComponent : LDC "<init>"
00013 ZosAssetFactoryManager [Z : TraceComponent String : LDC 0
00014 ZosAssetFactoryManager [Z : TraceComponent String I : ANEWARRAY java/lang/Object
00015 ZosAssetFactoryManager [Z : TraceComponent String [Object : INVOKESTATIC com/ibm/websphere/ras/Tr.entry (Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;[Ljava/lang/Object;)V
00016 ZosAssetFactoryManager [Z : : L0
00017 ZosAssetFactoryManager [Z : : FRAME FULL [com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager [Z] [] // ***** VALID *****
00018 ZosAssetFactoryManager [Z : : NOP
// END INJECTED TRACE
00019 ZosAssetFactoryManager [Z : : ALOAD 1
00020 ZosAssetFactoryManager [Z : [Z : ICONST_0
00021 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00022 ZosAssetFactoryManager [Z : [Z I I : BASTORE
00023 ZosAssetFactoryManager [Z : : ALOAD 0
00024 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : NEW java/util/HashMap
00025 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : DUP
00026 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap HashMap : INVOKESPECIAL java/util/HashMap.<init> ()V
00027 ZosAssetFactoryManager [Z : ZosAssetFactoryManager HashMap : PUTFIELD com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.assetFactories : Ljava/util/Map;
00028 ZosAssetFactoryManager [Z : : ALOAD 1
00029 ZosAssetFactoryManager [Z : [Z : ICONST_1
00030 ZosAssetFactoryManager [Z : [Z I : ICONST_1
00031 ZosAssetFactoryManager [Z : [Z I I : BASTORE
// BEGIN INJECTED TRACE
00032 ZosAssetFactoryManager [Z : : INVOKESTATIC com/ibm/websphere/ras/TraceComponent.isAnyTracingEnabled ()Z
00033 ZosAssetFactoryManager [Z : I : IFEQ L1
00034 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00035 ZosAssetFactoryManager [Z : TraceComponent : IFNULL L1
00036 ZosAssetFactoryManager [Z : : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00037 ZosAssetFactoryManager [Z : TraceComponent : INVOKEVIRTUAL com/ibm/websphere/ras/TraceComponent.isEntryEnabled ()Z
00038 ZosAssetFactoryManager [Z : I : IFEQ L1
00039 ZosAssetFactoryManager [Z : : ALOAD 0
00040 ZosAssetFactoryManager [Z : ZosAssetFactoryManager : ALOAD 0
00041 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : SWAP
00042 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager : GETSTATIC com/ibm/zosconnect/engine/impl/ZosAssetFactoryManager.tc : Lcom/ibm/websphere/ras/TraceComponent;
00043 ZosAssetFactoryManager [Z : ZosAssetFactoryManager ZosAssetFactoryManager TraceComponent : SWAP
00044 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager : LDC "<init>"
00045 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent ZosAssetFactoryManager String : SWAP
00046 ZosAssetFactoryManager [Z : ZosAssetFactoryManager TraceComponent String ZosAssetFactoryManager : INVOKESTATIC com/ibm/websphere/ras/Tr.exit (Ljava/lang/Object;Lcom/ibm/websphere/ras/TraceComponent;Ljava/lang/String;Ljava/lang/Object;)V
00047 ZosAssetFactoryManager [Z : : L1
00048 ZosAssetFactoryManager [Z : : FRAME SAME
// END INJECTED TRACE
00049 ZosAssetFactoryManager [Z : : RETURN