How Safari crashes the graphics driver
Setting the stage
It all started when we began getting reports of really weird behavior in Safari — something like this:
Glitches when moving objects on a board, unresponsive board rendering on the macOS app, frozen macOS, kernel panic.
Now what?
Let’s tell Apple
The first report we submitted to Apple: 222723 — Canvas Memory Leak
We reported it to Apple, but on second thought we didn’t identify the right root cause. Now I believe that this issue hasn’t got anything to do with memory.
Let’s research
We wanted to give Apple a reproducible example of the issue, so that they wouldn’t need to dig in our Miro app.
After some analysis, we believed that the problem had something to do with rendering: either DOM elements, or Canvas2D. We disabled all DOM elements, but the bug persisted. We had only one suspect left: Canvas2D.
The board was most likely producing a set of calls to the Canvas2D APIs that were triggering the bug, so we wrote a script to save all calls to the Canvas2D API during the rendering of the board. This produced about 20 MB of JS code, with only board calls to the Canvas2D API.
And we got it! We could reproduce the bug without needing the Miro app! That was a great success. We couldn’t possibly send Apple a report with a 20 MB HTML file, so we got rid of irrelevant calls. After a couple of days of painstaking trial and error, we had about 30 lines of code that can blow up a whole system to kernel panic when they run in Safari.
The smoking gun
We produced a working test case for this bug; it’s just about 30 lines of code:
The second report we submitted to Apple: 229136 — Canvas artifacts and system instability (including kernel panics) when drawing to a canvas
Important criteria for reproduction
After some experimenting, we discovered one important requirement to successfully reproduce the bug: a MacBook with an integrated graphics card. It’s a default setting on Big Sur; on Catalina, you enable it by running this command:
sudo pmset -c gpuswitch 0
Integrated graphics vs discrete graphics
To learn more about integrated graphics and discrete graphics, read this article:
What Is the Difference Between Integrated Graphics and Discrete…
Why does it happen?
The only thing we know for sure is that it has something to do with Canvas2D and the Intel HD card. Anything besides that is pure speculation: maybe a bug in the Intel HD driver? Maybe Safari uses the Intel HD driver incorrectly?
Since this bug can cause a kernel panic and it can really mess up app rendering in macOS, this is something potentially dangerous, so it must occur at low level.
Visualizing the process
We can visually represent the process we used with a diagram like this:
The outcome so far
Apple could reproduce the bug. They say that it’s not a bug in Safari or in its engine (WebKit), but a bug in a low-level framework. They fixed it in Monterey, which is currently in Beta.
We installed Monterey Beta 12 on our MacBook, and we can confirm that we can no longer reproduce the bug. There is one concern though: in the development process of the future Monterey releases, this bug could resurface, and it could crawl its way to a release version of Monterey — we’ll be watchful.
Join our team!
Would you like to be an Engineer at Miro? Check out opportunities to join the Engineering team.