Skip to content

Commit e6b1a59

Browse files
Domoniondenis-fokin
authored andcommitted
Kryo race fix (#1968)
[utbot-interprocess] 1. fixing race in inter-process communication: if multiple request accesses kryo when it writes message - kryo might increment some internal object graph fields in unpredictable order, causing serialized value become severely corrupted. This bug might be the reason for many other hard traceble bugs. 2. minor refactoring and build fixes (cherry picked from commit 953dc8f)
1 parent 11dfe2f commit e6b1a59

File tree

7 files changed

+18
-27
lines changed

7 files changed

+18
-27
lines changed

gradle.properties

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ apacheCommonsExecVersion=1.2
5757
apacheCommonsTextVersion=1.9
5858
rgxgenVersion=1.3
5959
antlrVersion=4.9.2
60-
kryoVersion=5.3.0
60+
kryoVersion=5.4.0
6161
kryoSerializersVersion=0.45
6262
asmVersion=9.2
6363
testNgVersion=7.6.0

utbot-framework/src/main/kotlin/org/utbot/framework/process/EngineProcessMain.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,8 @@ private fun EngineProcessModel.setup(kryoHelper: KryoHelper, watchdog: IdleWatch
170170
}
171171
watchdog.measureTimeForActiveCall(findMethodParamNames, "Find method parameters names") { params ->
172172
val classId = kryoHelper.readObject<ClassId>(params.classId)
173-
val byMethodDescription = kryoHelper.readObject<Map<MethodDescription, List<String>>>(params.bySignature)
173+
val bySignatureRaw = kryoHelper.readObject<List<Pair<MethodDescription, List<String>>>>(params.bySignature)
174+
val byMethodDescription = bySignatureRaw.associate { it.first to it.second }
174175
FindMethodParamNamesResult(kryoHelper.writeObject(classId.jClass.allNestedClasses.flatMap { clazz -> clazz.id.allMethods.mapNotNull { it.method.kotlinFunction } }
175176
.mapNotNull { method -> byMethodDescription[method.methodDescription()]?.let { params -> method.executableId to params } }
176177
.toMap()))

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/util/KryoHelper.kt

+10-24
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import com.esotericsoftware.kryo.kryo5.util.DefaultInstantiatorStrategy
1212
import com.jetbrains.rd.util.lifetime.Lifetime
1313
import com.jetbrains.rd.util.lifetime.throwIfNotAlive
1414
import java.io.ByteArrayOutputStream
15+
import java.util.concurrent.locks.ReentrantLock
16+
import kotlin.concurrent.withLock
1517

1618
/**
1719
* Helpful class for working with the kryo.
@@ -24,36 +26,17 @@ class KryoHelper constructor(
2426
private val kryoInput= Input()
2527
private val sendKryo: Kryo = TunedKryo()
2628
private val receiveKryo: Kryo = TunedKryo()
29+
private val myLockObject = ReentrantLock()
2730

2831
init {
32+
sendKryo.setAutoReset(true)
33+
receiveKryo.setAutoReset(true)
2934
lifetime.onTermination {
3035
kryoInput.close()
3136
kryoOutput.close()
3237
}
3338
}
3439

35-
fun <T> register(clazz: Class<T>, serializer: Serializer<T>) {
36-
sendKryo.register(clazz, serializer)
37-
receiveKryo.register(clazz, serializer)
38-
}
39-
40-
private fun <T> addInstantiatorOnKryo(kryo: Kryo, clazz: Class<T>, factory: () -> T) {
41-
val instantiator = kryo.instantiatorStrategy
42-
kryo.instantiatorStrategy = object : InstantiatorStrategy {
43-
override fun <R : Any?> newInstantiatorOf(type: Class<R>): ObjectInstantiator<R> {
44-
return if (type === clazz) {
45-
ObjectInstantiator<R> { factory() as R }
46-
}
47-
else
48-
instantiator.newInstantiatorOf(type)
49-
}
50-
}
51-
}
52-
fun <T> addInstantiator(clazz: Class<T>, factory: () -> T) {
53-
addInstantiatorOnKryo(sendKryo, clazz, factory)
54-
addInstantiatorOnKryo(receiveKryo, clazz, factory)
55-
}
56-
5740
fun setKryoClassLoader(classLoader: ClassLoader) {
5841
sendKryo.classLoader = classLoader
5942
receiveKryo.classLoader = classLoader
@@ -64,7 +47,7 @@ class KryoHelper constructor(
6447
*
6548
* @throws WritingToKryoException wraps all exceptions
6649
*/
67-
fun <T> writeObject(obj: T): ByteArray {
50+
fun <T> writeObject(obj: T): ByteArray = myLockObject.withLock {
6851
lifetime.throwIfNotAlive()
6952
try {
7053
sendKryo.writeClassAndObject(kryoOutput, obj)
@@ -84,14 +67,17 @@ class KryoHelper constructor(
8467
*
8568
* @throws ReadingFromKryoException wraps all exceptions
8669
*/
87-
fun <T> readObject(byteArray: ByteArray): T {
70+
fun <T> readObject(byteArray: ByteArray): T = myLockObject.withLock {
8871
lifetime.throwIfNotAlive()
8972
return try {
9073
kryoInput.buffer = byteArray
9174
receiveKryo.readClassAndObject(kryoInput) as T
9275
} catch (e: Exception) {
9376
throw ReadingFromKryoException(e)
9477
}
78+
finally {
79+
receiveKryo.reset()
80+
}
9581
}
9682
}
9783

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/generator/CodeGenerationController.kt

+1
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ object CodeGenerationController {
242242
)
243243
}
244244
}
245+
245246
private fun createUtilityClassIfNeeded(
246247
utilClassListener: UtilClassListener,
247248
model: GenerateTestsModel,

utbot-intellij/src/main/kotlin/org/utbot/intellij/plugin/process/EngineProcess.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ class EngineProcess private constructor(val project: Project, private val classN
223223

224224
val bySignature = executeWithTimeoutSuspended {
225225
DumbService.getInstance(project).runReadActionInSmartMode(Computable {
226-
methods.associate { it.methodDescription() to it.paramNames() }
226+
methods.map { it.methodDescription() to it.paramNames() }
227227
})
228228
}
229229
val arguments = FindMethodParamNamesArguments(

utbot-maven/build.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ task generatePluginDescriptor(type: JavaExec, dependsOn: [compileKotlin, generat
119119
}
120120
}
121121

122+
classes.dependsOn(generatePluginDescriptor)
123+
122124
publishing {
123125
publications {
124126
pluginMaven(MavenPublication) {

utbot-sample/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ dependencies {
66
implementation group: 'org.jetbrains', name: 'annotations', version: '16.0.2'
77
implementation group: 'com.github.stephenc.findbugs', name: 'findbugs-annotations', version: '1.3.9-1'
88
implementation 'org.projectlombok:lombok:1.18.20'
9+
testImplementation 'org.mockito:mockito-core:4.2.0'
910
annotationProcessor 'org.projectlombok:lombok:1.18.20'
1011
implementation(project(":utbot-api"))
1112
implementation group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'

0 commit comments

Comments
 (0)