ArrayIndexOutOfBoundsException while initializing mocks
Open
jitendra1331
opened this issue 6 years ago
•
11 comments
Version of JMockit that was used: 1.43
*Java Version : openjdk version "11.0.3" 2019-04-16 LTS
OpenJDK Runtime Environment Corretto-11.0.3.7.1 (build 11.0.3+7-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.3.7.1 (build 11.0.3+7-LTS, mixed mode)
Gradle version 5.3.1
javaagent configuration done correctly.
Getting below stack trace with java 11 environment. the same setup works fine for jdk8.
at java.lang.ArrayIndexOutOfBoundsException.(ArrayIndexOutOfBoundsException.java:52)
at mockit.asm.util.BytecodeReader.readUnsignedShort(BytecodeReader.java:130)
at mockit.asm.classes.ClassReader.skipClassMembers(ClassReader.java:254)
at mockit.asm.classes.ClassReader.getAttributesStartIndex(ClassReader.java:240)
at mockit.asm.classes.ClassReader.positionAtBootstrapMethodsAttribute(ClassReader.java:269)
at mockit.asm.classes.ClassWriter.(ClassWriter.java:77)
at mockit.internal.BaseClassModifier.(BaseClassModifier.java:40)
at mockit.internal.expectations.mocking.MockedClassModifier.(MockedClassModifier.java:42)
at mockit.internal.expectations.mocking.BaseTypeRedefinition.createClassModifier(BaseTypeRedefinition.java:151)
at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineClassAndItsSuperClasses(BaseTypeRedefinition.java:182)
at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineMethodsAndConstructorsInTargetType(BaseTypeRedefinition.java:176)
at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineTargetClassAndCreateInstanceFactory(BaseTypeRedefinition.java:248)
at mockit.internal.expectations.mocking.BaseTypeRedefinition.redefineType(BaseTypeRedefinition.java:68)
at mockit.internal.expectations.mocking.TypeRedefinition.redefineType(TypeRedefinition.java:28)
at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldType(FieldTypeRedefinitions.java:78)
at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldType(FieldTypeRedefinitions.java:65)
at mockit.internal.expectations.mocking.FieldTypeRedefinitions.redefineFieldTypes(FieldTypeRedefinitions.java:53)
at mockit.internal.expectations.mocking.FieldTypeRedefinitions.(FieldTypeRedefinitions.java:33)
at mockit.integration.TestRunnerDecorator.handleMockFieldsForWholeTestClass(TestRunnerDecorator.java:142)
at mockit.integration.TestRunnerDecorator.updateTestClassState(TestRunnerDecorator.java:40)
at mockit.integration.junit4.JUnit4TestRunnerDecorator.handleMockingOutsideTestMethods(JUnit4TestRunnerDecorator.java:129)
at mockit.integration.junit4.JUnit4TestRunnerDecorator.invokeExplosively(JUnit4TestRunnerDecorator.java:37)
at mockit.integration.junit4.FakeFrameworkMethod.invokeExplosively(FakeFrameworkMethod.java:29)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93)
at com.sun.proxy.$Proxy5.processTestClass(Unknown Source:-1)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-1)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:566)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175)
at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157)
at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404)
at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63)
at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55)
at java.lang.Thread.run(Thread.java:834)
The issue occurs when jacoco is also added as javaagent for instrumentation Even after the exclution pattern of excludes = ['$Impl_'] , it goes not work
Jacoco version 0.8.4
In that case, this look more like a JaCoCo issue, since JMockit is reading the modified bytecode that it wrote, and hitting some unexpected bytecode structure, on Java 11. Use of Gradle is probably unrelated.
I see a jacoco and jmockit compatibility issue, but it seems to have been fixed long long ago (https://github.com/jacoco/jacoco/pull/272).
Any idea why this is surfacing on Java 11 again.
My agent config is - javaagent:/Users/****/.gradle/caches/modules-2/files-2.1/org.jmockit/jmockit/1.43/656929cb778b6d60c46777fc13e5ffa52e68e66c/jmockit-1.43.jar -javaagent:build/tmp/expandedArchives/org.jacoco.agent-0.8.4.jar_982888894296538c98d7324f3ca78d8f/jacocoagent.jar
Can the ordering of the javaagent configs be a probable cause ?
Are you aware of any config for jacoco to disable jmockit modified bytecode from instrumentation
As explained in https://github.com/jacoco/jacoco/issues/896#issuecomment-500944865 JMockit should be fixed to properly handle condy (https://openjdk.java.net/jeps/309). As a temporary workaround while waiting for the fix in JMockit, you can use JaCoCo version 0.8.3 which doesn't produce condy.
@rliesenfeld don't know if this is enough for testing, but in absence of real reproducers from others, here is at least one that I quickly crafted when issue was reported in JaCoCo tracker - example.zip, essentially to reproduce this issue it is enough to execute JaCoCo 0.8.4 with any tests that use JMockit for mocking of Java 11+ class files - JaCoCo will add ldc with CONSTANT_Dynamic at the beginning of each method.
Also as an idea - class file transformer that will be changing bytecode version to 55 and replacing all getstatic for final fiels on ldc whose bootstrap method is java.lang.invoke.ConstantBootstraps.getStaticFinal, so that condy can be present in a projects even without JaCoCo. Or one that will be adding at random/some places ldc with bootstrap method java.lang.invoke.ConstantBootstraps.nullConstant immediately followed by pop.