InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
9.09k stars 719 forks source link

Concurrent modification exception when closing a scope #2058

Open dasdranagon opened 4 days ago

dasdranagon commented 4 days ago

Our iOS application occasionally crashes with ConcurrentModificationException.

Uncaught Kotlin exception: kotlin.ConcurrentModificationException
    at 0   kfun:kotlin.Exception#<init>(kotlin.String?;kotlin.Throwable?){} + 143 
    at 1   kfun:kotlin.RuntimeException#<init>(kotlin.String?;kotlin.Throwable?){} + 143 
    at 2   kfun:kotlin.ConcurrentModificationException#<init>(kotlin.String?;kotlin.Throwable?){} + 143 
    at 3   kfun:kotlin.ConcurrentModificationException#<init>(){} + 99 
    at 4   kfun:kotlin.collections.HashMap.Itr#checkForComodification(){} + 247 
    at 5   kfun:kotlin.collections.HashMap.ValuesItr#next(){}1:1 + 219 
    at 6   kfun:kotlin.collections.MutableIterator#next(){}1:0-trampoline + 99 
    at 7   kfun:co.touchlab.stately.collections.ConcurrentMutableIterator.next$lambda$1#internal + 143 
    at 8   kfun:co.touchlab.stately.collections.ConcurrentMutableIterator.$next$lambda$1$FUNCTION_REFERENCE$13.invoke#internal + 79 
    at 9   kfun:kotlin.Function0#invoke(){}1:0-trampoline + 99 
    at 10  kfun:co.touchlab.stately.concurrency.Synchronizable#runSynchronized(kotlin.Function0<0:0>){0§<kotlin.Any?>}0:0 + 355 
    at 11  kfun:co.touchlab.stately.collections.ConcurrentMutableIterator#next(){}1:0 + 271 
    at 12  kfun:kotlin.collections.Iterator#next(){}1:0-trampoline + 99 
    at 13  kfun:org.koin.core.registry.InstanceRegistry#dropScopeInstances(org.koin.core.scope.Scope){} + 459
    at 14  kfun:org.koin.core.registry.ScopeRegistry#deleteScope(org.koin.core.scope.Scope){} + 231 
    at 15  kfun:org.koin.core.scope.Scope.close$lambda$5#internal + 871 
    at 16  kfun:org.koin.core.scope.Scope.$close$lambda$5$FUNCTION_REFERENCE$4.invoke#internal + 71 
    at 17  kfun:org.koin.core.scope.Scope.$close$lambda$5$FUNCTION_REFERENCE$4.$<bridge-DNN>invoke(){}#internal + 71 
    at 18  kfun:kotlin.Function0#invoke(){}1:0-trampoline + 99 
    at 19  kfun:org.koin.mp.KoinPlatformTools#synchronized(org.koin.mp.Lockable;kotlin.Function0<0:0>){0§<kotlin.Any?>}0:0 + 375 
    at 20  kfun:org.koin.core.scope.Scope#close(){} + 223 

Methods like createAllEagerInstances and close in InstanceRegistry can cause concurrent mutation because using an iterator over a collection will cause an exception even if ConcurrentMutableMap was used. We assume that reimplementing access to _instances in a way similar to createAllEagerInstances (in the same file) should solve the problem.

Koin module and version: koin-core:3.5.6