High firefox Logic Error 🔧 Commit mapped

Overview

High
Severity
—
CVSS
No
Exploited ITW
Fixed
Fix Status
Impacthigh
DescriptionUse-after-free in the Layout: Grid component
ComponentLayout
Bug ClassLogic Error
Tracker2076983
Fix commitb585040adde7 (firefox) +29/-7
CISA KEVNot listed
CreditedMozilla
Disclosed2026-10-27

Files Changed

  • layout/generic/nsGridContainerFrame.cpp
  • testing/web-platform/tests/css/css-grid/observer-chain-crash.html
diff --git a/layout/generic/nsGridContainerFrame.cpp b/layout/generic/nsGridContainerFrame.cpp
index 35e7c105e69..982c82ac197 100644
--- a/layout/generic/nsGridContainerFrame.cpp
+++ b/layout/generic/nsGridContainerFrame.cpp
@@ -5752,21 +5752,20 @@ static nscoord MeasuringReflow(nsIFrame* aChild,
       nsIFrame::ReflowChildFlags::NoMoveFrame |
       nsIFrame::ReflowChildFlags::NoDeleteNextInFlowChild;
 
-  // Reflowing the child might invalidate the cache, so we declare the variable
-  // inside the if-statement to ensure it isn't accessed after it may have
-  // become invalid.
-  if (const GridItemCachedBAxisMeasurement* cachedMeasurement =
+  // NOTE: Reflowing or FinishReflowChild might invalidate the cache.
+  if (const auto* cache =
           aChild->GetProperty(GridItemCachedBAxisMeasurement::Prop());
       cachedMeasurement && cachedMeasurement->IsValidFor(aChild, aCBSize)) {
-    childSize.BSize(wm) = cachedMeasurement->BSize();
+    const nscoord cachedBSize = cachedMeasurement->BSize();
+    childSize.BSize(wm) = cachedBSize;
     childSize.ISize(wm) = aChild->ISize(wm);
     nsContainerFrame::FinishReflowChild(aChild, pc, childSize, &childRI, wm,
                                         LogicalPoint(wm), nsSize(), flags);
     GRID_LOG(
         "[perf] MeasuringReflow accepted cached value=%d, child=%p, "
         "aCBSize.ISize=%d",
-        cachedMeasurement->BSize(), aChild, aCBSize.ISize(wm));
-    return cachedMeasurement->BSize();
+        cachedBSize, aChild, aCBSize.ISize(wm));
+    return cachedBSize;
   }
 
   parent->ReflowChild(aChild, pc, childSize, childRI, wm, LogicalPoint(wm),
diff --git a/testing/web-platform/tests/css/css-grid/observer-chain-crash.html b/testing/web-platform/tests/css/css-grid/observer-chain-crash.html
new file mode 100644
index 00000000000..ea5a60459e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/observer-chain-crash.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html class="tets-wait">
+<style>
+#grid{display:grid;grid-template-columns:100px;align-items:start}
+</style>
+<svg width="100" height="40">
+<linearGradient id="paint" href="#item"><stop stop-color="red"/><stop offset="1" stop-color="blue"/></linearGradient>
+<path id="curve" d="M0 0H90V35H0Z" fill="url(#paint)"/>
+</svg>
+<div id="grid"><div id="item"><svg width="70" height="50"><defs><text><textPath href="#curve">x</textPath></text></defs></svg></div><div id="sibling">x</div></div>
+<script>
+async function run() {
+  const grid = document.getElementById("grid");
+  grid.getBoundingClientRect();
+  await new Promise(resolve => requestAnimationFrame(resolve));
+  await new Promise(resolve => setTimeout(resolve, 100));
+  document.getElementById("sibling").firstChild.data += "x";
+  grid.getBoundingClientRect();
+  document.documentElement.className = "";
+}
+run();
+</script>
+</html>
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/testing/web-platform/tests/css/css-grid/observer-chain-crash.html b/testing/web-platform/tests/css/css-grid/observer-chain-crash.html
new file mode 100644
index 00000000000..ea5a60459e8
--- /dev/null
+++ b/testing/web-platform/tests/css/css-grid/observer-chain-crash.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<html class="tets-wait">
+<style>
+#grid{display:grid;grid-template-columns:100px;align-items:start}
+</style>
+<svg width="100" height="40">
+<linearGradient id="paint" href="#item"><stop stop-color="red"/><stop offset="1" stop-color="blue"/></linearGradient>
+<path id="curve" d="M0 0H90V35H0Z" fill="url(#paint)"/>
+</svg>
+<div id="grid"><div id="item"><svg width="70" height="50"><defs><text><textPath href="#curve">x</textPath></text></defs></svg></div><div id="sibling">x</div></div>
+<script>
+async function run() {
+  const grid = document.getElementById("grid");
+  grid.getBoundingClientRect();
+  await new Promise(resolve => requestAnimationFrame(resolve));
+  await new Promise(resolve => setTimeout(resolve, 100));
+  document.getElementById("sibling").firstChild.data += "x";
+  grid.getBoundingClientRect();
+  document.documentElement.className = "";
+}
+run();
+</script>
+</html>
Loading diff…