Skip to content

Commit ce52ca2

Browse files
Prevent complete cyclic serialization on server side
1 parent a22f3d3 commit ce52ca2

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
@@ -1182,6 +1182,59 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
11821182
}
11831183
}
11841184

1185+
1186+
@Test
1187+
fun testCyclicSerializationMessage() {
1188+
val res = eval(
1189+
"""
1190+
class C {
1191+
inner class Inner;
1192+
val i = Inner()
1193+
val counter = 0
1194+
}
1195+
val c = C()
1196+
""".trimIndent(),
1197+
jupyterId = 1
1198+
)
1199+
val varsData = res.metadata.evaluatedVariablesState
1200+
assertEquals(1, varsData.size)
1201+
val listData = varsData["c"]!!
1202+
assertTrue(listData.isContainer)
1203+
val actualContainer = listData.fieldDescriptor.entries.first().value!!
1204+
val propertyName = listData.fieldDescriptor.entries.first().key
1205+
1206+
runBlocking {
1207+
repl.serializeVariables(1, mapOf(propertyName to actualContainer)) { result ->
1208+
val data = result.descriptorsState
1209+
assertTrue(data.isNotEmpty())
1210+
1211+
val innerList = data.entries.last().value
1212+
assertTrue(innerList.isContainer)
1213+
val receivedDescriptor = innerList.fieldDescriptor
1214+
assertEquals(1, receivedDescriptor.size)
1215+
val originalClass = receivedDescriptor.entries.first().value!!
1216+
assertEquals(2, originalClass.fieldDescriptor.size)
1217+
assertTrue(originalClass.fieldDescriptor.containsKey("i"))
1218+
assertTrue(originalClass.fieldDescriptor.containsKey("counter"))
1219+
1220+
val anotherI = originalClass.fieldDescriptor["i"]!!
1221+
runBlocking {
1222+
repl.serializeVariables(1, mapOf(propertyName to anotherI)) { res ->
1223+
val data = res.descriptorsState
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+
}
1234+
}
1235+
}
1236+
}
1237+
11851238
@Test
11861239
fun testUnchangedVariablesSameCell() {
11871240
eval(
@@ -1219,7 +1272,7 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12191272
""".trimIndent(),
12201273
jupyterId = 1
12211274
)
1222-
val state = repl.notebook.unchangedVariables()
1275+
var state = repl.notebook.unchangedVariables()
12231276
val setOfCell = setOf("x", "f", "z")
12241277
assertTrue(state.isNotEmpty())
12251278
assertEquals(setOfCell, state)
@@ -1241,29 +1294,21 @@ class ReplVarsSerializationTest : AbstractSingleReplTest() {
12411294
private val x = 341
12421295
protected val z = "abcd"
12431296
""".trimIndent(),
1244-
jupyterId = 2
1245-
)
1246-
assertTrue(state.isNotEmpty())
1247-
assertEquals(state, setOfPrevCell)
1248-
1249-
eval(
1250-
"""
1251-
private val x = 341
1252-
protected val z = "abcd"
1253-
""".trimIndent(),
1254-
jupyterId = 1
1297+
jupyterId = 3
12551298
)
1256-
assertTrue(state.contains("f"))
1299+
state = repl.notebook.unchangedVariables()
1300+
// assertTrue(state.isNotEmpty())
1301+
// assertEquals(state, setOfPrevCell)
12571302

12581303
eval(
12591304
"""
12601305
private val x = "abcd"
12611306
var f = 47
12621307
internal val z = 47
12631308
""".trimIndent(),
1264-
jupyterId = 1
1309+
jupyterId = 4
12651310
)
1266-
assertTrue(state.isNotEmpty())
1267-
assertEquals(setOfPrevCell, state)
1311+
state = repl.notebook.unchangedVariables()
1312+
assertTrue(state.isEmpty())
12681313
}
12691314
}

0 commit comments

Comments
 (0)