[19] PlatformScreen data-race / GPUCanvasContextCocoa worker race
Severity: Medium | Component: WebCore PlatformScreen | 08911bd, cf20d12
Rated Medium because the two related diffs fix concurrent HashMap access on the process-global ScreenProperties singleton; readers on worker threads iterated screenDataMap.values() while the main thread rehashed it — surfaced as MTE tag-mismatch crashes on ARM hardware.
Two co-discovered fixes for the same root cause. The first (cf20d12) adds ASSERT(isMainThread()) to the existing screenProperties() accessor and dispatches off-main-thread GPUCanvasContextCocoa reads through callOnMainThread + BinarySemaphore. The second (08911bd) makes the fix structural: replaces the NeverDestroyed<ScreenProperties> accessor with a ThreadSafeRefCounted<PlatformScreen> singleton accessed via Ref<const PlatformScreen>, with copy-on-write semantics under platformScreenLock().
Source/WebCore/platform/PlatformScreen.cpp
-static ScreenProperties& NODELETE screenProperties()
-{
- ASSERT(isMainThread());
- static NeverDestroyed<ScreenProperties> screenProperties;
- return screenProperties;
-}
+Ref<const PlatformScreen> PlatformScreen::singleton()
+{
+ Locker locker { platformScreenLock() };
+ return instance().get();
+}
+void PlatformScreen::updateSingletonProperties(ScreenProperties&& properties)
+{
+ Locker locker { platformScreenLock() };
+ Ref<PlatformScreen>& platformScreenRef = PlatformScreen::instance();
+ if (platformScreenRef->hasOneRef())
+ platformScreenRef->m_properties = WTF::move(properties);
+ else
+ platformScreenRef = PlatformScreen::create(WTF::move(properties));
+}
Patch Details
Free-standing screenData(), getScreenProperties(), primaryScreenDisplayID(), setScreenProperties() are deleted. PlatformScreen becomes a ThreadSafeRefCounted class; writers swap a fresh instance into the slot when there are concurrent readers; readers snapshot a Ref<const PlatformScreen> and keep it alive via refcount. All call sites (HTMLMediaElement, GPUCanvasContextCocoa, VP9/GStreamer scanners, PlatformScreen{Mac,iOS,GTK,WPE}) migrate to PlatformScreen::singleton()->....
Data race / use-after-free on a singleton HashMap whose readers escape pointers and iterators into the backing storage while another thread mutates it.
PlatformScreen is a per-process cache mirroring per-display state (rectangles, EDR headroom, color space) keyed by PlatformDisplayID. UIProcess pushes updates via WebProcess::setScreenProperties, which previously called the file-scope setter and overwrote the singleton. WTF HashMap is not thread-safe: concurrent insert or operator= can rehash the bucket array (freeing the old one), invalidating any iterator a concurrent reader holds.
Aaa Aaaaaaa Aaaaaaa Aa Aaaaaaaaaa a Aaaaaaaaaaa Aaaaa Aaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaaaaaa Aaaaaaa Aa Aaa Aaaaaaaaaa Aaaaaa Aaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaa Aaaa Aaa Aaa Aaa Aaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aa Aaa Aaaa Aaaaa Aaaaaaaa Aaa Aaaaaaaaaa Aaaa Aaaa Aaaaaaaaa Aa Aaaaa Aaaaaa Aaaa Aaaaaaaaa Aaa Aaaaaa Aa a Aaaaaa Aaaa Aaaa a Aaaaaaaa Aaaa Aa Aaa Aaaaaaaaa Aaaaaa Aa Aaaaa Aaaaaaa Aaaaaaaaa Aaa Aaaaaaaaaaaaaaaaaaaa a Aaa Aaaaaaa Aa Aaaaaaaa Aaa Aaaaaaaaa Aaaaaaaaaaaa
Aaaa Aaaaaaaaaaaaa Aaaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaaa Aaaa Aaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaaaa Aaaaa Aa Aaaaaaaaaaaaaaaa a Aaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaaaaaa Aaaaaa Aaaaa Aaaaaa a Aaaaaaaaaaaaaaaaa Aaaaaa Aaaaa Aaaaaa a Aaaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaa Aaaaaaaaaa
🔒The threading and ownership model behind this singleton rewrite is dissected, including how the copy-on-write fast path interacts with concurrent readers.
Subscribe to read more
Audit directions
a Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaa Aaaaaaa Aaaa Aa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaa Aaa Aaaaaaa Aaa Aaaaaaa Aaaaaaaaaaaaaaaa a Aaaaaaaaaa Aaaaaaaaaaa Aaaaa Aaaaaaa Aaa Aaaaaaaaaaaaaaa Aaaaaaaaaaaaa
a Aaaaaaaaaaa Aaa Aaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaa Aaa Aaaaaaaaaaaaa Aaaa Aaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaa Aaaaaaaaaaaaa Aaaaaaaaa Aaaaaaaa Aa Aaaaaa a Aaaaaaaa a Aaaaaaa Aaaaaaaaa
a Aaaaaaaaaaaa Aaaaa Aaaaaaa Aaaaaaaa Aaaaaaaaaa Aaaaa Aaaaaaaa Aaaaaaaaaa Aaaaaaa Aaaaa Aaaaaaaaaaaaaaaaaa Aaaaaaaa Aaaaaaaaaaa Aaaaaaaaaaaaaaaa Aaaaaaaaaaa
a Aaaaaaaaaaaaaaa Aaaaaaaaaaaaaaaaaaaaaaaaaaa Aaaaaaaaaaa Aaaaaa Aaaaaaaaaaaaa a Aaaaaaaa Aaaaaaaa Aa Aaaaaaaa Aaaa Aaaaa Aaa Aaaa a Aa Aaaaa Aaaaaa Aaa Aaaa Aaaa Aaaaaaaa Aaa Aaa Aaa Aaaaaaa a Aaa Aaaa Aaaaaaa Aaa Aaaaa Aaa Aaa Aaaaaaaaa
🔒Four reusable audit patterns covering singleton caches, escaped HashMap pointers, IPC-driven mutation, and copy-on-write fast paths.
Subscribe to read more