| Newsgroups |
gmane.comp.java.objectweb.asm |
| Message-ID |
<[email protected]> |
This is a multi-part message in MIME format...
------------=_1681834429-16686-10
Content-Type: text/plain; charset="US-ASCII"
Content-Transfer-Encoding: 7BIT
Content-length: 14094
Hi everyone,
I tried to enable `CheckClassAdapter` with `checkDataFlow` set to `true` to
make sure that my instrumentation is valid. However, I encountered an issue
that even original classes from third party libraries are considered invalid.
As an example the method `getCanonicalName` in the class `AssertionUtils` in
JUnit 5.9.2:
```pom.xml
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>9.5</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.2</version>
<scope>test</scope>
</dependency>
```
```java
@Test
void assertionUtils() throws Exception {
String classRes = "/org/junit/jupiter/api/AssertionUtils.class";
byte[] classfileBuffer;
try (InputStream is = MyTest.class.getResourceAsStream(classRes)) {
classfileBuffer = IOUtils.toByteArray(is);
}
ClassReader reader = new ClassReader(classfileBuffer);
TraceClassVisitor trace = new TraceClassVisitor(null, new Textifier(),
new PrintWriter(System.err));
reader.accept(trace, 0);
reader = new ClassReader(classfileBuffer);
ClassWriter writer = new ClassWriter(reader, 0);
CheckClassAdapter checker = new CheckClassAdapter(writer, true);
try {
reader.accept(checker, 0);
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
Class.forName("org.junit.jupiter.api.AssertionUtils");
}
```
This unit test passes the byte content for `AssertionUtils` without
instrumentation or modification into a `ClassReader`, outputs the byte code
using `TraceClassVisitor` and then independently runs it through
`CheckClassAdapter`. The output of this test is as follows:
```
// `TraceClassVisitor` output
// class version 52.0 (52)
// access flags 0x20
class org/junit/jupiter/api/AssertionUtils {
// ...
// access flags 0x8
// signature (Ljava/lang/Class<*>;)Ljava/lang/String;
// declaration: java.lang.String getCanonicalName(java.lang.Class<?>)
static getCanonicalName(Ljava/lang/Class;)Ljava/lang/String;
TRYCATCHBLOCK L0 L1 L2 java/lang/Throwable
L0
LINENUMBER 59 L0
ALOAD 0
INVOKEVIRTUAL java/lang/Class.getCanonicalName ()Ljava/lang/String;
ASTORE 1
L3
LINENUMBER 60 L3
ALOAD 1
IFNULL L4
ALOAD 1
GOTO L1
L4
FRAME APPEND [java/lang/String]
ALOAD 0
INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
L1
FRAME SAME1 java/lang/String
ARETURN
L2
LINENUMBER 62 L2
FRAME FULL [java/lang/Class] [java/lang/Throwable]
ASTORE 1
L5
LINENUMBER 63 L5
ALOAD 1
INVOKESTATIC org/junit/platform/commons/util/
UnrecoverableExceptions.rethrowIfUnrecoverable (Ljava/lang/Throwable;)V
L6
LINENUMBER 64 L6
ALOAD 0
INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
ARETURN
L7
LOCALVARIABLE canonicalName Ljava/lang/String; L3 L2 1
LOCALVARIABLE t Ljava/lang/Throwable; L5 L7 1
LOCALVARIABLE clazz Ljava/lang/Class; L0 L7 0
// signature Ljava/lang/Class<*>;
// declaration: clazz extends java.lang.Class<?>
MAXSTACK = 1
MAXLOCALS = 2
// ...
}
// `e.printStackTrace();` for `IllegalArgumentException`
java.lang.IllegalArgumentException: Error at instruction 12: Cannot append
more locals than maxLocals getCanonicalName(Ljava/lang/Class;)Ljava/lang/
String;
00000 R . : : L0
00001 ? : LINENUMBER 59 L0
00002 ? : ALOAD 0
00003 ? : INVOKEVIRTUAL java/lang/Class.getCanonicalName ()Ljava/lang/
String;
00004 ? : ASTORE 1
00005 ? : L1
00006 ? : LINENUMBER 60 L1
00007 ? : ALOAD 1
00008 ? : IFNULL L2
00009 ? : ALOAD 1
00010 ? : GOTO L3
00011 ? : L2
00012 ? : FRAME APPEND [java/lang/String]
00013 ? : ALOAD 0
00014 ? : INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
00015 ? : L3
00016 ? : FRAME SAME1 java/lang/String
00017 ? : ARETURN
00018 ? : L4
00019 ? : LINENUMBER 62 L4
00020 ? : FRAME FULL [java/lang/Class] [java/lang/Throwable]
00021 ? : ASTORE 1
00022 ? : L5
00023 ? : LINENUMBER 63 L5
00024 ? : ALOAD 1
00025 ? : INVOKESTATIC org/junit/platform/commons/util/
UnrecoverableExceptions.rethrowIfUnrecoverable (Ljava/lang/Throwable;)V
00026 ? : L6
00027 ? : LINENUMBER 64 L6
00028 ? : ALOAD 0
00029 ? : INVOKEVIRTUAL java/lang/Class.getName ()Ljava/lang/String;
00030 ? : ARETURN
00031 ? : L7
TRYCATCHBLOCK L0 L3 L4 java/lang/Throwable
at org.objectweb.asm.util.CheckMethodAdapter
$1.throwError(CheckMethodAdapter.java:489)
at org.objectweb.asm.util.CheckMethodAdapter
$1.visitEnd(CheckMethodAdapter.java:475)
at org.objectweb.asm.MethodVisitor.visitEnd(MethodVisitor.java:796)
at
org.objectweb.asm.util.CheckMethodAdapter.visitEnd(CheckMethodAdapter.java:1044)
at org.objectweb.asm.ClassReader.readMethod(ClassReader.java:1518)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:744)
at org.objectweb.asm.ClassReader.accept(ClassReader.java:424)
at
net.lacework.caa.java.instrument.TracepointClassFileTransformerTest.assertionUtils(TracepointClassFileTransformerTest.java:98)
at java.base/
jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at
org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
at
org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain
$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at
org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
at
org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
at
org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
at org.junit.jupiter.engine.execution.InterceptingExecutableInvoker
$ReflectiveInterceptorCall.lambda$ofVoidMethod
$0(InterceptingExecutableInvoker.java:103)
at
org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke
$0(InterceptingExecutableInvoker.java:93)
at org.junit.jupiter.engine.execution.InvocationInterceptorChain
$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at
org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at
org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at
org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at
org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
at
org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda
$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
at
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
at
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
at
org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$6(NodeTestTask.java:151)
at
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$8(NodeTestTask.java:141)
at
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$9(NodeTestTask.java:139)
at
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$6(NodeTestTask.java:155)
at
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$8(NodeTestTask.java:141)
at
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$9(NodeTestTask.java:139)
at
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$6(NodeTestTask.java:155)
at
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$8(NodeTestTask.java:141)
at
org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda
$executeRecursively$9(NodeTestTask.java:139)
at
org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at
org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at
org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at
org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at
org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at
org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:147)
at
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:127)
at
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:90)
at org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda
$execute$0(EngineExecutionOrchestrator.java:55)
at
org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:102)
at
org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:54)
at
org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at
org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:95)
at org.junit.platform.launcher.core.DefaultLauncherSession
$DelegatingLauncher.execute(DefaultLauncherSession.java:91)
at
org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:60)
at
org.eclipse.jdt.internal.junit5.runner.JUnit5TestReference.run(JUnit5TestReference.java:98)
at
org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:40)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:529)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:756)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:452)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:210)
Caused by: org.objectweb.asm.tree.analysis.AnalyzerException: Error at
instruction 12: Cannot append more locals than maxLocals
at
org.objectweb.asm.util.CheckFrameAnalyzer.expandFrames(CheckFrameAnalyzer.java:240)
at
org.objectweb.asm.util.CheckFrameAnalyzer.init(CheckFrameAnalyzer.java:124)
at org.objectweb.asm.tree.analysis.Analyzer.analyze(Analyzer.java:142)
at org.objectweb.asm.util.CheckMethodAdapter
$1.visitEnd(CheckMethodAdapter.java:470)
... 74 more
Caused by: org.objectweb.asm.tree.analysis.AnalyzerException: Cannot append
more locals than maxLocals
at
org.objectweb.asm.util.CheckFrameAnalyzer.expandFrame(CheckFrameAnalyzer.java:277)
at
org.objectweb.asm.util.CheckFrameAnalyzer.expandFrames(CheckFrameAnalyzer.java:237)
... 77 more
```
The class loads without issues in
`Class.forName("org.junit.jupiter.api.AssertionUtils");`, complaining that the
`FRAME APPEND` on offset `12` exceeds the maximum of 2 local variables. Given
that the preceding implicit init frame based on the single argument and the
fact that it is a `static` method should have 1 local variable, my
understanding is that this is not actually the case and that the bytecode is
valid. I see similar errors like this for multiple classes in JUnit and other
JARs.
Conversely, this check works as well:
```
reader = new ClassReader(classfileBuffer);
CheckClassAdapter.verify(reader,
TracepointClassFileTransformerTest.class.getClassLoader(), false, new
PrintWriter(System.err));
```
Thus my question: Am I misusing the `CheckClassAdapter` or the `Analyzer` API
somehow? Or is this a bug in the analysis?
Thanks,
------------=_1681834429-16686-10
Content-Type: text/plain; charset="UTF-8"
Content-Disposition: inline
Content-Transfer-Encoding: 8bit
--
You receive this message as a subscriber of the [email protected] mailing list.
To unsubscribe: mailto:[email protected]
For general help: mailto:[email protected]?subject=help
OW2 mailing lists service home page: http://www.ow2.org/wws
------------=_1681834429-16686-10--