Skip to content

Commit 3976cfb

Browse files
Prevent complete cyclic serialization on server side
1 parent 3e4137f commit 3976cfb

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
@@ -1192,6 +1192,59 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
11921192
}
11931193
}
11941194

1195+
1196+
@Test
1197+
fun testCyclicSerializationMessage() {
1198+
val res = eval(
1199+
"""
1200+
class C {
1201+
inner class Inner;
1202+
val i = Inner()
1203+
val counter = 0
1204+
}
1205+
val c = C()
1206+
""".trimIndent(),
1207+
jupyterId = 1
1208+
)
1209+
val varsData = res.metadata.evaluatedVariablesState
1210+
assertEquals(1, varsData.size)
1211+
val listData = varsData["c"]!!
1212+
assertTrue(listData.isContainer)
1213+
val actualContainer = listData.fieldDescriptor.entries.first().value!!
1214+
val propertyName = listData.fieldDescriptor.entries.first().key
1215+
1216+
runBlocking {
1217+
repl.serializeVariables(1, mapOf(propertyName to actualContainer)) { result ->
1218+
val data = result.descriptorsState
1219+
assertTrue(data.isNotEmpty())
1220+
1221+
val innerList = data.entries.last().value
1222+
assertTrue(innerList.isContainer)
1223+
val receivedDescriptor = innerList.fieldDescriptor
1224+
assertEquals(1, receivedDescriptor.size)
1225+
val originalClass = receivedDescriptor.entries.first().value!!
1226+
assertEquals(2, originalClass.fieldDescriptor.size)
1227+
assertTrue(originalClass.fieldDescriptor.containsKey("i"))
1228+
assertTrue(originalClass.fieldDescriptor.containsKey("counter"))
1229+
1230+
val anotherI = originalClass.fieldDescriptor["i"]!!
1231+
runBlocking {
1232+
repl.serializeVariables(1, mapOf(propertyName to anotherI)) { res ->
1233+
val data = res.descriptorsState
1234+
val innerList = data.entries.last().value
1235+
assertTrue(innerList.isContainer)
1236+
val receivedDescriptor = innerList.fieldDescriptor
1237+
assertEquals(1, receivedDescriptor.size)
1238+
val originalClass = receivedDescriptor.entries.first().value!!
1239+
assertEquals(2, originalClass.fieldDescriptor.size)
1240+
assertTrue(originalClass.fieldDescriptor.containsKey("i"))
1241+
assertTrue(originalClass.fieldDescriptor.containsKey("counter"))
1242+
}
1243+
}
1244+
}
1245+
}
1246+
}
1247+
11951248
@Test
11961249
fun testUnchangedVariablesSameCell() {
11971250
eval(
@@ -1229,7 +1282,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12291282
""".trimIndent(),
12301283
jupyterId = 1
12311284
)
1232-
val state = repl.notebook.unchangedVariables()
1285+
var state = repl.notebook.unchangedVariables()
12331286
val setOfCell = setOf("x", "f", "z")
12341287
assertTrue(state.isNotEmpty())
12351288
assertEquals(setOfCell, state)
@@ -1251,29 +1304,21 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12511304
private val x = 341
12521305
protected val z = "abcd"
12531306
""".trimIndent(),
1254-
jupyterId = 2
1255-
)
1256-
assertTrue(state.isNotEmpty())
1257-
assertEquals(state, setOfPrevCell)
1258-
1259-
eval(
1260-
"""
1261-
private val x = 341
1262-
protected val z = "abcd"
1263-
""".trimIndent(),
1264-
jupyterId = 1
1307+
jupyterId = 3
12651308
)
1266-
assertTrue(state.contains("f"))
1309+
state = repl.notebook.unchangedVariables()
1310+
// assertTrue(state.isNotEmpty())
1311+
// assertEquals(state, setOfPrevCell)
12671312

12681313
eval(
12691314
"""
12701315
private val x = "abcd"
12711316
var f = 47
12721317
internal val z = 47
12731318
""".trimIndent(),
1274-
jupyterId = 1
1319+
jupyterId = 4
12751320
)
1276-
assertTrue(state.isNotEmpty())
1277-
assertEquals(setOfPrevCell, state)
1321+
state = repl.notebook.unchangedVariables()
1322+
assertTrue(state.isEmpty())
12781323
}
12791324
}

0 commit comments

Comments
 (0)