Skip to content

Commit

Permalink
Prevents a stackoverflow when creating a view graph cycle (#1771)
Browse files Browse the repository at this point in the history
  • Loading branch information
soywiz authored Jul 6, 2023
1 parent eb62d05 commit 47ad4b9
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 0 deletions.
10 changes: 10 additions & 0 deletions korge/src/commonMain/kotlin/korlibs/korge/view/Container.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package korlibs.korge.view
import korlibs.datastructure.*
import korlibs.datastructure.iterators.*
import korlibs.event.*
import korlibs.io.lang.*
import korlibs.korge.internal.*
import korlibs.korge.render.*
import korlibs.korge.view.property.*
Expand Down Expand Up @@ -395,12 +396,21 @@ open class Container(
stage?.views?.invalidatedView(this)
}


internal fun checkValidChild(child: View) {
val parent = this
if (parent === child) invalidOp("Can't addChild to itself")
if (parent.hasAncestor(child)) invalidOp("Can't addChild to an ancestor")
}

/**
* Adds the [view] [View] as a child at a specific [index].
*
* Remarks: if [index] is outside bounds 0..[numChildren], it will be clamped to the nearest valid value.
*/
fun addChildAt(view: View, index: Int) {
checkValidChild(view)

view.parent?.invalidateZIndexChildren()
view.removeFromParent()
val aindex = index.clamp(0, this.numChildren)
Expand Down
25 changes: 25 additions & 0 deletions korge/src/commonTest/kotlin/korlibs/korge/view/ViewTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package korlibs.korge.view

import assertEqualsFloat
import korlibs.image.bitmap.*
import korlibs.io.lang.*
import korlibs.korge.tests.*
import korlibs.math.geom.*
import kotlin.test.*
Expand Down Expand Up @@ -280,4 +281,28 @@ class ViewTest {
logs.joinToString("\n")
)
}

@Test
fun testViewAddToItself() {
val text = Text("hello")
assertEquals(
"Can't addChild to itself",
assertFailsWith<InvalidOperationException> { text.addChild(text) }.message
)
assertNull(text.parent)
}

@Test
fun testViewCreateCycle() {
val container1 = Container()
val container2 = Container()
val container3 = Container()
container1.addChild(container2)
container2.addChild(container3)
assertEquals(
"Can't addChild to an ancestor",
assertFailsWith<InvalidOperationException> { container3.addChild(container1) }.message
)
assertNull(container1.parent)
}
}

0 comments on commit 47ad4b9

Please sign in to comment.