From 47ad4b912fc0854a90868002b3a1cea3bbbb7634 Mon Sep 17 00:00:00 2001 From: Carlos Ballesteros Velasco Date: Thu, 6 Jul 2023 08:23:06 +0200 Subject: [PATCH] Prevents a stackoverflow when creating a view graph cycle (#1771) --- .../kotlin/korlibs/korge/view/Container.kt | 10 ++++++++ .../kotlin/korlibs/korge/view/ViewTest.kt | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/korge/src/commonMain/kotlin/korlibs/korge/view/Container.kt b/korge/src/commonMain/kotlin/korlibs/korge/view/Container.kt index 802ad38cbe..96c39cb096 100644 --- a/korge/src/commonMain/kotlin/korlibs/korge/view/Container.kt +++ b/korge/src/commonMain/kotlin/korlibs/korge/view/Container.kt @@ -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.* @@ -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) diff --git a/korge/src/commonTest/kotlin/korlibs/korge/view/ViewTest.kt b/korge/src/commonTest/kotlin/korlibs/korge/view/ViewTest.kt index c5c369227d..0fafac16e9 100644 --- a/korge/src/commonTest/kotlin/korlibs/korge/view/ViewTest.kt +++ b/korge/src/commonTest/kotlin/korlibs/korge/view/ViewTest.kt @@ -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.* @@ -280,4 +281,28 @@ class ViewTest { logs.joinToString("\n") ) } + + @Test + fun testViewAddToItself() { + val text = Text("hello") + assertEquals( + "Can't addChild to itself", + assertFailsWith { 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 { container3.addChild(container1) }.message + ) + assertNull(container1.parent) + } }