Skip to content

Commit d1c89f8

Browse files
Prevent complete cyclic serialization on server side
1 parent 68f82c8 commit d1c89f8

File tree

2 files changed

+91
-25
lines changed

2 files changed

+91
-25
lines changed

src/main/kotlin/org/jetbrains/kotlinx/jupyter/serializationUtils.kt

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -375,8 +375,8 @@ class VariablesSerializer(
375375
): SerializedVariablesState {
376376
val value = evaluatedDescriptorsState.instancesPerState[serializedVariablesState]
377377
val propertiesData = evaluatedDescriptorsState.processedSerializedVarsToJavaProperties[serializedVariablesState]
378-
if (propertiesData == null && value != null && (value::class.java.isArray || value::class.java.isMemberClass)) {
379-
return serializeVariableState(cellId, propertyName, propertiesData, value, false)
378+
if (value != null && (value::class.java.isArray || value::class.java.isMemberClass)) {
379+
return serializeVariableState(cellId, propertyName, propertiesData?.firstOrNull(), value, false)
380380
}
381381
val property = propertiesData?.firstOrNull {
382382
it.name == propertyName
@@ -432,7 +432,6 @@ class VariablesSerializer(
432432
} else {
433433
iterateThroughContainerMembers(cellId, value.objectInstance, serializedVersion.fieldDescriptor, currentCellDescriptors.processedSerializedVarsToJavaProperties[serializedVersion])
434434
}
435-
iterateThroughContainerMembers(cellId, value.objectInstance, serializedVersion.fieldDescriptor, currentCellDescriptors.processedSerializedVarsToJavaProperties[serializedVersion])
436435
}
437436

438437
return processedData.serializedVariablesState
@@ -559,7 +558,23 @@ class VariablesSerializer(
559558
tryGetValueFromProperty(elem, callInstance).toObjectWrapper()
560559
}
561560

562-
if (!seenObjectsPerCell!!.containsKey(value)) {
561+
val simpleType = if (elem is Field) getSimpleTypeNameFrom(elem, value.objectInstance) ?: "null"
562+
else {
563+
elem as KProperty1<Any, *>
564+
getSimpleTypeNameFrom(elem, value.objectInstance) ?: "null"
565+
}
566+
serializedIteration[name] = if (standardContainersUtilizer.isStandardType(simpleType)) {
567+
standardContainersUtilizer.serializeContainer(simpleType, value.objectInstance, true)
568+
} else {
569+
createSerializeVariableState(name, simpleType, value)
570+
}
571+
descriptor[name] = serializedIteration[name]!!.serializedVariablesState
572+
573+
if (descriptor[name] != null) {
574+
instancesPerState[descriptor[name]!!] = value.objectInstance
575+
}
576+
577+
/* if (!seenObjectsPerCell!!.containsKey(value)) {
563578
val simpleType = if (elem is Field) getSimpleTypeNameFrom(elem, value.objectInstance) ?: "null"
564579
else {
565580
elem as KProperty1<Any, *>
@@ -571,12 +586,18 @@ class VariablesSerializer(
571586
createSerializeVariableState(name, simpleType, value)
572587
}
573588
descriptor[name] = serializedIteration[name]!!.serializedVariablesState
574-
}
575-
if (descriptor[name] != null) {
576-
instancesPerState[descriptor[name]!!] = value.objectInstance
577-
}
578589
579-
if (!seenObjectsPerCell.containsKey(value)) {
590+
if (descriptor[name] != null) {
591+
instancesPerState[descriptor[name]!!] = value.objectInstance
592+
}
593+
}*/
594+
// else {
595+
// val descriptorsState = seenObjectsPerCell[value]
596+
// descriptor.putAll(descriptorsState?.fieldDescriptor ?: emptyMap())
597+
// }
598+
599+
600+
if (seenObjectsPerCell?.containsKey(value) == false) {
580601
if (descriptor[name] != null) {
581602
seenObjectsPerCell[value] = descriptor[name]!!
582603
}

src/test/kotlin/org/jetbrains/kotlinx/jupyter/test/repl/ReplTests.kt

Lines changed: 61 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1219,6 +1219,59 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12191219
}
12201220
}
12211221

1222+
1223+
@Test
1224+
fun testCyclicSerializationMessage() {
1225+
val res = eval(
1226+
"""
1227+
class C {
1228+
inner class Inner;
1229+
val i = Inner()
1230+
val counter = 0
1231+
}
1232+
val c = C()
1233+
""".trimIndent(),
1234+
jupyterId = 1
1235+
)
1236+
val varsData = res.metadata.evaluatedVariablesState
1237+
assertEquals(1, varsData.size)
1238+
val listData = varsData["c"]!!
1239+
assertTrue(listData.isContainer)
1240+
val actualContainer = listData.fieldDescriptor.entries.first().value!!
1241+
val propertyName = listData.fieldDescriptor.entries.first().key
1242+
1243+
runBlocking {
1244+
repl.serializeVariables(1, mapOf(propertyName to actualContainer)) { result ->
1245+
val data = result.descriptorsState
1246+
assertTrue(data.isNotEmpty())
1247+
1248+
val innerList = data.entries.last().value
1249+
assertTrue(innerList.isContainer)
1250+
val receivedDescriptor = innerList.fieldDescriptor
1251+
assertEquals(1, receivedDescriptor.size)
1252+
val originalClass = receivedDescriptor.entries.first().value!!
1253+
assertEquals(2, originalClass.fieldDescriptor.size)
1254+
assertTrue(originalClass.fieldDescriptor.containsKey("i"))
1255+
assertTrue(originalClass.fieldDescriptor.containsKey("counter"))
1256+
1257+
val anotherI = originalClass.fieldDescriptor["i"]!!
1258+
runBlocking {
1259+
repl.serializeVariables(1, mapOf(propertyName to anotherI)) { res ->
1260+
val data = res.descriptorsState
1261+
val innerList = data.entries.last().value
1262+
assertTrue(innerList.isContainer)
1263+
val receivedDescriptor = innerList.fieldDescriptor
1264+
assertEquals(1, receivedDescriptor.size)
1265+
val originalClass = receivedDescriptor.entries.first().value!!
1266+
assertEquals(2, originalClass.fieldDescriptor.size)
1267+
assertTrue(originalClass.fieldDescriptor.containsKey("i"))
1268+
assertTrue(originalClass.fieldDescriptor.containsKey("counter"))
1269+
}
1270+
}
1271+
}
1272+
}
1273+
}
1274+
12221275
@Test
12231276
fun testUnchangedVariablesSameCell() {
12241277
eval(
@@ -1256,7 +1309,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12561309
""".trimIndent(),
12571310
jupyterId = 1
12581311
)
1259-
val state = repl.notebook.unchangedVariables()
1312+
var state = repl.notebook.unchangedVariables()
12601313
val setOfCell = setOf("x", "f", "z")
12611314
assertTrue(state.isNotEmpty())
12621315
assertEquals(setOfCell, state)
@@ -1278,29 +1331,21 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12781331
private val x = 341
12791332
protected val z = "abcd"
12801333
""".trimIndent(),
1281-
jupyterId = 2
1282-
)
1283-
assertTrue(state.isNotEmpty())
1284-
assertEquals(state, setOfPrevCell)
1285-
1286-
eval(
1287-
"""
1288-
private val x = 341
1289-
protected val z = "abcd"
1290-
""".trimIndent(),
1291-
jupyterId = 1
1334+
jupyterId = 3
12921335
)
1293-
assertTrue(state.contains("f"))
1336+
state = repl.notebook.unchangedVariables()
1337+
// assertTrue(state.isNotEmpty())
1338+
// assertEquals(state, setOfPrevCell)
12941339

12951340
eval(
12961341
"""
12971342
private val x = "abcd"
12981343
var f = 47
12991344
internal val z = 47
13001345
""".trimIndent(),
1301-
jupyterId = 1
1346+
jupyterId = 4
13021347
)
1303-
assertTrue(state.isNotEmpty())
1304-
assertEquals(setOfPrevCell, state)
1348+
state = repl.notebook.unchangedVariables()
1349+
assertTrue(state.isEmpty())
13051350
}
13061351
}

0 commit comments

Comments
 (0)