Skip to content

Commit ec951f7

Browse files
Fix recursion detection
1 parent f9a67d5 commit ec951f7

File tree

2 files changed

+55
-9
lines changed
  • jupyter-lib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api
  • src/test/kotlin/org/jetbrains/kotlinx/jupyter/test/repl

2 files changed

+55
-9
lines changed

jupyter-lib/api/src/main/kotlin/org/jetbrains/kotlinx/jupyter/api/VariableState.kt

+28-9
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ data class VariableStateImpl(
3939
}
4040
}
4141
override var isRecursive: Boolean = false
42+
private var isLargeForString: Boolean = false
4243

4344
private val valCache = VariableStateCache<Result<Any?>> (
4445
{
@@ -73,17 +74,35 @@ data class VariableStateImpl(
7374
val res = action(this)
7475
isAccessible = wasAccessible
7576
return res
76-
private val customDelegate = DependentLazyDelegate {
77-
fun getRecursiveObjectName(): String {
78-
val kClassName = cachedValue.getOrNull()!!::class.simpleName
79-
return "$kClassName: recursive structure"
8077
}
81-
if (cachedValue.getOrNull() == null) {
82-
return@DependentLazyDelegate null
83-
}
84-
handleIfRecursiveStructure()
8578
}
86-
}
79+
private val customDelegate = DependentLazyDelegate {
80+
fun getRecursiveObjectName(): String {
81+
val kClassName = cachedValue.getOrNull()!!::class.simpleName
82+
return "$kClassName: recursive structure"
83+
}
84+
if (cachedValue.getOrNull() == null) {
85+
return@DependentLazyDelegate null
86+
}
87+
handleIfRecursiveStructure()
88+
try {
89+
cachedValue.getOrNull().toString()
90+
isRecursive = false
91+
isLargeForString = false
92+
} catch (e: VirtualMachineError) {
93+
when (e) {
94+
is StackOverflowError -> {
95+
isRecursive = true
96+
}
97+
is OutOfMemoryError -> {
98+
isLargeForString = true
99+
}
100+
else -> {
101+
return@DependentLazyDelegate null
102+
}
103+
}
104+
}
105+
}
87106

88107
private class VariableStateCache<T>(
89108
val equalityChecker: (T, T) -> Boolean = { x, y -> x == y },

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

+27
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,33 @@ class ReplVarsTest : AbstractSingleReplTest() {
774774
assertEquals(2, newData.fieldDescriptor.size)
775775
}
776776

777+
@Test
778+
fun testProperBiRecursionHandling() {
779+
eval(
780+
"""
781+
val l = mutableListOf<Any>()
782+
l.add(listOf(l))
783+
784+
val m = mutableMapOf<Int, Any>(1 to l)
785+
786+
val z = setOf(1, 2, 4)
787+
""".trimIndent(),
788+
jupyterId = 1
789+
)
790+
var state = repl.notebook.variablesState
791+
assertEquals("ArrayList: recursive structure", state["l"]!!.stringValue)
792+
assertEquals("LinkedHashMap: recursive structure", state["m"]!!.stringValue)
793+
eval(
794+
"""
795+
val m = mutableMapOf<Int, Any>(1 to "abc")
796+
""".trimIndent(),
797+
jupyterId = 2
798+
)
799+
state = repl.notebook.variablesState
800+
assertEquals("ArrayList: recursive structure", state["l"]!!.stringValue)
801+
assertNotEquals("LinkedHashMap: recursive structure", state["m"]!!.stringValue)
802+
}
803+
777804
@Test
778805
fun testUnchangedVars() {
779806
eval(

0 commit comments

Comments
 (0)