Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug: StackOverflowError in case of complex annotation checks involving HashMap calls #337

Open
HuppiFluppi opened this issue Jul 25, 2019 · 17 comments

Comments

@HuppiFluppi
Copy link

Expected Behavior

Class should be mocked w/o errors

Current Behavior

Stackoverflow Exception stops execution

Failure Information (for bugs)

I try to mockk a class which has a default ctor with several interfaces. The 'to be mocked' class itself is a Spring Component (annotated), the interfaces for the ctor are Spring Repositories (annotated). Running the tests produces the mentioned StackOverflowError. Commenting out the mockk<> removes the error.

Steps to Reproduce

Project with Mockk (1.9.3), Spring Boot(2.1.6)/Framework(5.1.8), Spring Mongo(2.1.9) and Junit (4.12).

See code below.

Context

Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions.

  • MockK version: 1.9.3
  • OS: Windows 10 1903
  • Kotlin version: 1.3.41
  • JDK version: 1.8
  • JUnit version: 4.12
  • Type of test: unit test

Failure Logs

Stack trace

Exception in thread "main" java.lang.StackOverflowError
	at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936)
	at io.mockk.proxy.jvm.dispatcher.JvmMockKDispatcher.get(JvmMockKDispatcher.java:16)
	at java.lang.Object.hashCode(Object.java:119)
	at java.util.HashMap.hash(HashMap.java:339)
	at java.util.HashMap.get(HashMap.java:557)
	at sun.reflect.Reflection.filterMethods(Reflection.java:291)
	at java.lang.Class.getMethodHelper(Class.java:1261)
	at java.lang.Class.getMethod(Class.java:1187)
	at java.lang.Object.hashCode(Object.java:119)
	at java.util.HashMap.hash(HashMap.java:339)
	at java.util.HashMap.get(HashMap.java:557)
	at sun.reflect.Reflection.filterMethods(Reflection.java:291)
	at java.lang.Class.getMethodHelper(Class.java:1261)
	at java.lang.Class.getMethod(Class.java:1187)
---- lines repeat a lot -----
        at java.lang.Object.hashCode(Object.java:119)
	at java.util.HashMap.hash(HashMap.java:339)
	at java.util.LinkedHashMap.get(LinkedHashMap.java:440)
	at java.lang.Class.getAnnotation(Class.java:2181)
	at java.lang.Class.isAnnotationPresent(Class.java:2589)
	at org.junit.runner.notification.RunNotifier.wrapIfNotThreadSafe(RunNotifier.java:50)
	at org.junit.runner.notification.RunNotifier.removeListener(RunNotifier.java:42)
	at org.junit.runner.JUnitCore.removeListener(JUnitCore.java:161)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:140)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Exception in thread "Thread-5" java.lang.StackOverflowError
// -----------------------[ YOUR STACK TRACE ENDS HERE ] -----------------------

Minimal reproducible code (the gist of this issue)

// -----------------------[ GRADLE DEFINITIONS ] -----------------------
dependencies {
    implementation(kotlin("stdlib-jdk8"))
    implementation(kotlin("reflect"))
    implementation("org.springframework.boot:spring-boot-starter:2.1.6.RELEASE")
    implementation("org.springframework.boot:spring-boot-starter-data-mongodb:2.1.9.RELEASE")
    
    testImplementation("io.mockk:mockk:1.9.3")
    testImplementation(kotlin("test"))
    testImplementation(kotlin("test-junit"))

    testImplementation("org.springframework.boot:spring-boot-starter-test:2.1.6.RELEASE")
    testImplementation("junit:junit:4.12")
}
// -----------------------[ YOUR CODE STARTS HERE ] -----------------------
package io.mockk.gh

import io.mockk.mockk

import org.junit.Test
import org.springframework.beans.factory.annotation.Value
import org.springframework.data.mongodb.repository.MongoRepository
import org.springframework.stereotype.Component
import org.springframework.stereotype.Repository

interface AnotherInterface1
interface AnotherInterface2

class PersistencyClass1
class PersistencyClass2

@Repository
interface Repo1 : MongoRepository<PersistencyClass1, String>, AnotherInterface1

@Repository
interface Repo2 : MongoRepository<PersistencyClass2, String>, AnotherInterface2

@Component
class ToBeMocked(
        private val repo1: Repo1,
        private val repo2: Repo2,
        @Value("\${number:1000}") private val someNumber: Long)

class MockkTest {
    private val mockedObject = mockk<ToBeMocked>() //here it happens

    @Test
    fun dummyTst() {
        //no code needed to reproduce
    }
}
// -----------------------[ YOUR CODE ENDS HERE ] -----------------------
@HuppiFluppi
Copy link
Author

Ok, so i did some research and tried out some stuff. Turns out it is because of the installed JDK. I used
AdoptOpenJDK 1.8.0_212 openJ9 wich leads to the error.

I then tried out some configurations and came up with following list:

AdoptOpenJDK: 1.8.0_212 openJ9 -> FAIL
AdoptOpenJDK: 1.8.0_222 hotspot -> OK
AdoptOpenJDK: 1.8.0_222 openJ9 -> FAIL
AdoptOpenJDK: 11.0.1+13 openJ9 -> OK
AdoptOpenJDK: 11.0.4+11 openJ9 -> FAIL
AdoptOpenJDK: 11.0.4+11 hotspot -> OK

Overall the hotspot variants are working. I leave it up to Mockk team whether you want to look into supporting openJ9. I switched to hotspot for now.

So long, Felix

@oleksiyp
Copy link
Collaborator

Thank you for your investigation

@To-da
Copy link

To-da commented Aug 1, 2019

Hi, I also facing the same issue when mocking Spring beans by @MockkBean (springmockk).
It indeed fail only on openJ9, hotspot is ok.
Another observation is that it's failing only on CGLIB-based proxies. In case of injecting Interface (by default Spring will create JDK proxy) everything is ok.

@krobert
Copy link

krobert commented Aug 9, 2019

Its failing for me using 1.8.0_221-b11 hotspot.
Any workaround?

@BPaasch
Copy link

BPaasch commented Aug 27, 2019

I also have this same issue.
It fails for me using AdoptOpenJDK 8 u222 b10 OpenJ9.

I have found that I can use AdoptOpenJDK 8 u202 b08 OpenJ9 and it works fine.

@DanySK
Copy link

DanySK commented Oct 3, 2019

I hit the bug as well in one of my demo projects. The tests fail with a stack overflow if OpenJ9 is used. The failure is reproducible in both JDK12 and JDK8.

DanySK added a commit to Protelis/Protelis-Demo that referenced this issue Oct 3, 2019
@DanySK
Copy link

DanySK commented Oct 3, 2019

A more extensive test shows failures on OpenJ9 11 as well.

@oleksiyp oleksiyp changed the title Mockking class produces StackOverflowError StackOverflowError in case of complex annotation checks involving HashMap calls Nov 1, 2019
@oleksiyp oleksiyp added this to the 1.9.4 milestone Nov 1, 2019
@oleksiyp oleksiyp changed the title StackOverflowError in case of complex annotation checks involving HashMap calls Bug: StackOverflowError in case of complex annotation checks involving HashMap calls Nov 1, 2019
@oleksiyp oleksiyp added this to To do in Critical to fix Nov 2, 2019
@Elyahou
Copy link

Elyahou commented May 26, 2020

Is there any plan to fix this ? I have this same issue with OpenJ9 13

DanySK added a commit to Protelis/Protelis-Demo that referenced this issue May 27, 2020
This will get merged once mockk/mockk#337 is fixed.
github-actions bot pushed a commit to Protelis/Protelis-Demo that referenced this issue Jun 16, 2020
This will get merged once mockk/mockk#337 is fixed.
@DanySK
Copy link

DanySK commented Jun 18, 2020

Just so you know eclipse-openj9/openj9#9940 seems to be the same issue.

@DanySK
Copy link

DanySK commented Jun 18, 2020

Is there any hypothesis on why this happens, any workaround?

@DanHeidinga
Copy link

Is there any hypothesis on why this happens, any workaround?

My current theory is that it's due to the jacoco agent modifying the Object.hashCode() method to add instrumentation (record calls?) by adding context to a HashMap, which of course has to call Object.hashCode() to get the right hash bucket. This loops forever until the StackOverflow occurs.

A potential workaround is to not instrument Object using jacoco by adding excludes=java/lang/Object to the agent's option list.

github-actions bot pushed a commit to Protelis/Protelis-Demo that referenced this issue Jul 13, 2020
This will get merged once mockk/mockk#337 is fixed.
@realdadfish
Copy link

realdadfish commented Aug 10, 2020

This is unrelated to Jacoco, this is the minimal reproduction case I could come up with:

  • build.gradle
buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72"
    }
}

repositories {
    mavenCentral()
}

apply plugin: "kotlin"

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.72"

    testImplementation "junit:junit:4.13"
    testImplementation "io.mockk:mockk:1.10.0"
}
  • Example.kt
internal class Example 
  • ExampleTest.kt
import io.mockk.mockk
import org.junit.Test

class ExampleTest {
    @Test
    fun test() {
        mockk<Example>(relaxed = true)
    }
}
  • Versions:
$ ./gradlew -version 

------------------------------------------------------------
Gradle 6.5.1
------------------------------------------------------------

Build time:   2020-06-30 06:32:47 UTC
Revision:     66bc713f7169626a7f0134bf452abde51550ea0a

Kotlin:       1.3.72
Groovy:       2.5.11
Ant:          Apache Ant(TM) version 1.10.7 compiled on September 1 2019
JVM:          11.0.8 (Eclipse OpenJ9 openj9-0.21.0)
OS:           Mac OS X 10.15.6 x86_64

github-actions bot pushed a commit to Protelis/Protelis-Demo that referenced this issue Sep 1, 2020
This will get merged once mockk/mockk#337 is fixed.
github-actions bot pushed a commit to Protelis/Protelis-Demo that referenced this issue Sep 2, 2020
This will get merged once mockk/mockk#337 is fixed.
github-actions bot pushed a commit to Protelis/Protelis-Demo that referenced this issue Sep 2, 2020
This will get merged once mockk/mockk#337 is fixed.
github-actions bot pushed a commit to Protelis/Protelis-Demo that referenced this issue Oct 20, 2020
This will get merged once mockk/mockk#337 is fixed.
github-actions bot pushed a commit to Protelis/Protelis-Demo that referenced this issue Nov 17, 2020
This will get merged once mockk/mockk#337 is fixed.
@cmackenzie1
Copy link

Facing the same issue using docker pull gradle:6.8.0-jdk8-openj9

------------------------------------------------------------
Gradle 6.8
------------------------------------------------------------

Build time:   2021-01-08 16:38:46 UTC
Revision:     b7e82460c5373e194fb478a998c4fcfe7da53a7e

Kotlin:       1.4.20
Groovy:       2.5.12
Ant:          Apache Ant(TM) version 1.10.9 compiled on September 27 2020
JVM:          1.8.0_275 (Eclipse OpenJ9 openj9-0.23.0)
OS:           Linux 4.19.121-linuxkit amd64

@mimozell
Copy link

mimozell commented Mar 22, 2021

Seeing the same issue with 11.0.10.j9, but it works fine with 11.0.10.hs.

@HWiese1980
Copy link

Any news around here? The issue has been open for quite a while now and the problem seems to persist.

@HWiese1980
Copy link

HWiese1980 commented Jun 8, 2021

Weird, I've reinitialized my environment and the problem has vanished. I'm not quite sure what I actually did, otherwise I'd write it down here, of course, but whatever it was, it seems to have helped... All I did was switching my IntelliJ from adoptjdk-8.0.242+8.1 to adoptjdk-8.0.282+8 and back to 8.0.242+8.1 again (which definitely showed the stack overflow error before) and it suddenly started working again. What's even weirder is that the error had appeared out of nowhere. One day it worked, the next (today), it stopped.

@marugi
Copy link

marugi commented Jan 10, 2022

sdkman users should use version 11.0.10.hs-adpt for java 11 support - FYI
as this stackoverflow happens in other versions too

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

No branches or pull requests