Unverified Commit bb96b1f6 authored by Pavel's avatar Pavel Committed by GitHub

prevent usage of dangling pointer to `MetalDevice` (#666)

* prevent usage of dangling pointer to `MetalDevice`

MetalRedrawer may be disposed during update which leads to use after free

* add test and comment
parent b53f5d4a
...@@ -25,7 +25,11 @@ internal class MetalRedrawer( ...@@ -25,7 +25,11 @@ internal class MetalRedrawer(
} }
private var drawLock = Any() private var drawLock = Any()
private val device: Long private var device: Long
get() {
check(field != 0L) { "Device is not initialized" }
return field
}
val adapterName: String val adapterName: String
val adapterMemorySize: Long val adapterMemorySize: Long
...@@ -60,6 +64,7 @@ internal class MetalRedrawer( ...@@ -60,6 +64,7 @@ internal class MetalRedrawer(
frameDispatcher.cancel() frameDispatcher.cancel()
contextHandler.dispose() contextHandler.dispose()
disposeDevice(device) disposeDevice(device)
device = 0
super.dispose() super.dispose()
} }
...@@ -73,8 +78,10 @@ internal class MetalRedrawer( ...@@ -73,8 +78,10 @@ internal class MetalRedrawer(
inDrawScope { inDrawScope {
setVSyncEnabled(device, enabled = false) setVSyncEnabled(device, enabled = false)
update(System.nanoTime()) update(System.nanoTime())
performDraw() if (!isDisposed) { // Redrawer may be disposed in user code, during `update`
setVSyncEnabled(device, properties.isVsyncEnabled) performDraw()
setVSyncEnabled(device, properties.isVsyncEnabled)
}
} }
} }
......
...@@ -26,6 +26,7 @@ import java.awt.Dimension ...@@ -26,6 +26,7 @@ import java.awt.Dimension
import java.awt.event.WindowEvent import java.awt.event.WindowEvent
import javax.swing.JFrame import javax.swing.JFrame
import javax.swing.JLayeredPane import javax.swing.JLayeredPane
import javax.swing.SwingUtilities
import javax.swing.WindowConstants import javax.swing.WindowConstants
import kotlin.random.Random import kotlin.random.Random
import kotlin.test.assertNotNull import kotlin.test.assertNotNull
...@@ -508,6 +509,34 @@ class SkiaLayerTest { ...@@ -508,6 +509,34 @@ class SkiaLayerTest {
} }
} }
@Test
fun `frame disposed inside of immediate repaint`() = uiTest {
val onDrawCompleted = CompletableDeferred<Unit>()
val window = UiTestWindow(
properties = SkiaLayerProperties(
isVsyncEnabled = true,
isVsyncFramelimitFallbackEnabled = true
)
)
try {
window.setLocation(200, 200)
window.setSize(400, 400)
window.layer.skikoView = object : SkikoView {
override fun onRender(canvas: Canvas, width: Int, height: Int, nanoTime: Long) {
window.dispose()
SwingUtilities.invokeLater {
onDrawCompleted.complete(Unit)
}
}
}
window.isVisible = true
onDrawCompleted.await()
} finally {
window.dispose()
}
}
@Test @Test
fun `render text (Windows)`() { fun `render text (Windows)`() {
testRenderText(OS.Windows) testRenderText(OS.Windows)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment