[6] GFC `layoutGridItems` redundant measurement layouts
Low. A behavioral-divergence fix, not a memory-safety one: fit-content grid items were measured with extra forced layouts that each repainted the item, diverging from legacy RenderGrid. Likely not exploitable — the observable effect is spurious repaint invalidation, with no memory-safety direction on the available evidence.
The GFC is the LFC-based reimplementation of CSS Grid under Source/WebCore/layout/formattingContexts/grid, running the sizing algorithm and laying grid items out through an IntegrationUtils bridge into the legacy render tree, all in the WebContent process. For fit-content items it resolved the block size via a helper that runs intrinsic-size probe layouts on the live renderer, then laid the item out again with the measured height forced. The invariant that should hold: an item's published size comes from a single authoritative layout, with no extra render-tree mutation to re-derive it.
The angle: none offensive — the effect is extra repaint invalidations for fit-content grid items observable via paint-rect counts; the audit value is the pattern of intrinsic-size probes mutating live render-tree state.
Commit message / comment: for fit-content items blockUsedSize ran layout to compute min/max-content sizes as well, whereas RenderGrid "just calls layout on it". The fix routes these items through one unforced block-axis layout and reads the height back from geometry.
Source/WebCore/layout/formattingContexts/grid/GridLayout.cpp
Patch Details
The change stops resolving the block size of fit-content grid items via the measuring helper and instead performs one layout that is unforced in the block axis — layoutGridItem(..., inlineUsedSize, { }, gridAreaInlineSize) still forces the inline size — then reads contentBoxHeight() from the resulting box geometry, adding blockBorderAndPadding separately because the geometry's own padding was resolved against the grid container rather than the grid area.
Redundant measurement layouts over live render-tree state, whose side effects (repaint invalidation, dirty-bit churn) diverge from the authoritative single-layout path.
Background
GFC and the integration bridge. The GFC runs the grid sizing algorithm (GridSizer) and lays items out through IntegrationUtils into the legacy render tree, publishing rects via computeGridItemRects/setGridItemGeometries.
Intrinsic-size probes are not free reads. In this integration layer a measurement call mutates the live renderer — blockSizeForGridItem calls setGridAreaContentLogicalWidth(...), setNeedsLayout(MarkOnlyThis), layoutWithFormattingContextForBox(...), and clearGridAreaContentSize() before reading geometryForBox(box).borderBoxHeight(). That blockUsedSize funnels into that helper is taken from the comment this patch adds.
Coexisting legacy path. The added comment frames the change as matching what "RenderGrid just calls layout on it" does, implying the legacy RenderGrid implementation coexists during migration.
Analysis
This is a logic / behavioral-divergence error: redundant measurement passes over live render-tree state whose side effects are externally observable. It is not a memory-safety bug on the available evidence.
Each measurement layout marks the item for layout and lays it out, and the added test's description states each layout pass over the item repaints it at its old position. So with intrinsic-size measurement layouts preceding the final layout, the GFC path issued more repaint invalidations for a fit-content grid item than the path the comment attributes to RenderGrid. The new test pins the count at three rects (two at the item's old y=50, one at its new y=100 after align-self changes from start to end). The pre-fix rect count is not stated in the diff — the expectation file is new — so this fix is about aligning the integration-layer path with the layout count RenderGrid already produces, not about reducing to a specific target number. There is no memory-safety escalation direction here.
Audit directions
- Intrinsic-size probes that mutate live render-tree state. Helpers that call
setNeedsLayout/layoutWithFormattingContextForBoxon a live renderer purely to read a size back can leave observable dirty-bit and repaint side effects. Audit otherIntegrationUtilsmeasurement helpers that force a layout to derive a size that the authoritative pass already produces. In code review, asetNeedsLayout(...)followed by a probe layout and aclear...()inside a "get size" helper is the tell.