Skip to content

Commit 42751f2

Browse files
Prevent complete cyclic serialization on server side
1 parent 18e844c commit 42751f2

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
@@ -1195,6 +1195,59 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
11951195
}
11961196
}
11971197

1198+
1199+
@Test
1200+
fun testCyclicSerializationMessage() {
1201+
val res = eval(
1202+
"""
1203+
class C {
1204+
inner class Inner;
1205+
val i = Inner()
1206+
val counter = 0
1207+
}
1208+
val c = C()
1209+
""".trimIndent(),
1210+
jupyterId = 1
1211+
)
1212+
val varsData = res.metadata.evaluatedVariablesState
1213+
assertEquals(1, varsData.size)
1214+
val listData = varsData["c"]!!
1215+
assertTrue(listData.isContainer)
1216+
val actualContainer = listData.fieldDescriptor.entries.first().value!!
1217+
val propertyName = listData.fieldDescriptor.entries.first().key
1218+
1219+
runBlocking {
1220+
repl.serializeVariables(1, mapOf(propertyName to actualContainer)) { result ->
1221+
val data = result.descriptorsState
1222+
assertTrue(data.isNotEmpty())
1223+
1224+
val innerList = data.entries.last().value
1225+
assertTrue(innerList.isContainer)
1226+
val receivedDescriptor = innerList.fieldDescriptor
1227+
assertEquals(1, receivedDescriptor.size)
1228+
val originalClass = receivedDescriptor.entries.first().value!!
1229+
assertEquals(2, originalClass.fieldDescriptor.size)
1230+
assertTrue(originalClass.fieldDescriptor.containsKey("i"))
1231+
assertTrue(originalClass.fieldDescriptor.containsKey("counter"))
1232+
1233+
val anotherI = originalClass.fieldDescriptor["i"]!!
1234+
runBlocking {
1235+
repl.serializeVariables(1, mapOf(propertyName to anotherI)) { res ->
1236+
val data = res.descriptorsState
1237+
val innerList = data.entries.last().value
1238+
assertTrue(innerList.isContainer)
1239+
val receivedDescriptor = innerList.fieldDescriptor
1240+
assertEquals(1, receivedDescriptor.size)
1241+
val originalClass = receivedDescriptor.entries.first().value!!
1242+
assertEquals(2, originalClass.fieldDescriptor.size)
1243+
assertTrue(originalClass.fieldDescriptor.containsKey("i"))
1244+
assertTrue(originalClass.fieldDescriptor.containsKey("counter"))
1245+
}
1246+
}
1247+
}
1248+
}
1249+
}
1250+
11981251
@Test
11991252
fun testUnchangedVariablesSameCell() {
12001253
eval(
@@ -1232,7 +1285,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12321285
""".trimIndent(),
12331286
jupyterId = 1
12341287
)
1235-
val state = repl.notebook.unchangedVariables()
1288+
var state = repl.notebook.unchangedVariables()
12361289
val setOfCell = setOf("x", "f", "z")
12371290
assertTrue(state.isNotEmpty())
12381291
assertEquals(setOfCell, state)
@@ -1254,29 +1307,21 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12541307
private val x = 341
12551308
protected val z = "abcd"
12561309
""".trimIndent(),
1257-
jupyterId = 2
1258-
)
1259-
assertTrue(state.isNotEmpty())
1260-
assertEquals(state, setOfPrevCell)
1261-
1262-
eval(
1263-
"""
1264-
private val x = 341
1265-
protected val z = "abcd"
1266-
""".trimIndent(),
1267-
jupyterId = 1
1310+
jupyterId = 3
12681311
)
1269-
assertTrue(state.contains("f"))
1312+
state = repl.notebook.unchangedVariables()
1313+
// assertTrue(state.isNotEmpty())
1314+
// assertEquals(state, setOfPrevCell)
12701315

12711316
eval(
12721317
"""
12731318
private val x = "abcd"
12741319
var f = 47
12751320
internal val z = 47
12761321
""".trimIndent(),
1277-
jupyterId = 1
1322+
jupyterId = 4
12781323
)
1279-
assertTrue(state.isNotEmpty())
1280-
assertEquals(setOfPrevCell, state)
1324+
state = repl.notebook.unchangedVariables()
1325+
assertTrue(state.isEmpty())
12811326
}
12821327
}

0 commit comments

Comments
 (0)