jmockit1 icon indicating copy to clipboard operation
jmockit1 copied to clipboard

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)

jitendra1331 avatar Jun 03 '19 18:06 jitendra1331

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

jitendra1331 avatar Jun 04 '19 15:06 jitendra1331

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.

rliesenfeld avatar Jun 04 '19 15:06 rliesenfeld

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

jitendra1331 avatar Jun 04 '19 16:06 jitendra1331

That JaCoCo issue is about dynamically generated classes, and unrelated to this one.

Ordering of Javagent loading is irrelevant, and the order that instrumentation occurs at runtime cannot be changed.

You can always exclude a class that is going to be mocked from being instrumented by jacoco, through configuration. Or you can avoid mocking it.

rliesenfeld avatar Jun 05 '19 02:06 rliesenfeld

I'm hitting the same issue in JDK 11/12. In JDK 9 JaCoCo and JMockit works fine together.

willforevercn avatar Jun 11 '19 19:06 willforevercn

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.

Godin avatar Jun 11 '19 20:06 Godin

downgrade JaCoCo works great! Thanks very much!

willforevercn avatar Jun 11 '19 21:06 willforevercn

I will add support for CONSTANT_Dynamic. The real difficulty is testing this.

rliesenfeld avatar Jun 12 '19 16:06 rliesenfeld

@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.

Hope this helps.

Godin avatar Jun 12 '19 17:06 Godin

Just to mention, I tried with the latest master and I still get the same AIOOBE shown in #637

Vampire avatar Dec 06 '19 14:12 Vampire

I still face this issue with Jacoco 0.8.4 and JMockit 1.49 (Open JDK11). Do you when we can expect a fix for this issue.

smithaleslee avatar Feb 18 '20 19:02 smithaleslee