[Fix, Test] (Magma, MG_IntegrationTest): make the handle-ABA negative control construct its own collision and defeat the {slot, gen} generation

- MOBILEGL_PIPE_HANDLE_ABA_CONTROL asserted the corruption and saw correct pixels, so
  DirectVulkan.HandleRecycle.AbaControl.*AVertexArray* was RED in an always-on
  integration-gpu lane while every guard it was supposed to be defeating stood. Two
  measured reasons, neither of them the {slot, gen} re-key: (1) D18 spelled the control as
  "hash the raw BufferObject* instead of its lifetime id, and skip the vaoLifetimeId
  compare", which only collides if the allocator hands the freed block back - it does not.
  glGen* recycles the NAME, but a VertexArrayObject is 3920 bytes, past glibc's tcache, so
  its chunk goes to the unsorted bin and is split by the next allocation the replacement
  path makes; four create/delete cycles in one run gave four addresses ~1 MiB apart, and
  the BufferObject behaves the same. (2) The reproducer put a frame boundary between the
  arming draw and the recycled draw, and the only memo that carries a GPU slice rather
  than a layout - ResolvedVertexBindings - declines across frames by design, so no key
  collision whatsoever could have shown up in pixels.
- The control no longer asks the allocator for the collision: on both arms it replaces the
  object identity in DirectVulkan's vertex-input keys with a constant, which is the
  strongest form of "the block came back" and is deterministic. Three sites, all behind
  one question (MagmaPipeAbaControlDefeatsIdentity): the buffer identity leaves
  VertexInputStateFactory::ComputeHash, VertexInputStateFactory::MemosFor claims one entry
  without its Owner compare, and VulkanRenderer::LookupVaoDrawMemo hands one entry back
  uncleared ahead of both arms.
- That is what makes the control cover the key P2 SHIPS. Under MOBILEGL_PIPE_PUSH=0 the
  handle arm is not executed at all, so the old control said nothing about the generation
  in {slot, gen} - the whole of what makes the re-keyed memos ABA-safe. A second lane,
  DirectVulkan.HandleRecycle.AbaControlHandles., runs the handle arm with the knob and
  asserts the same corruption; D18's lane is kept verbatim beside it for the pre-handle arm.
- The reproducer's two draws now share a frame, and both buffers are realised before the
  window, so a moved slice epoch cannot mask the ABA behind a gate that is not about
  identity. Nothing else is relaxed: the frame serial, the slice epochs and the host-map
  check stay in force, so a green arm still means "a replacement object was handed its
  predecessor's resolved vertex bindings because the identity halves of the keys were
  defeated".
- ExpectPixelsFor now prints what it OBSERVED (STALE/FRESH/NEITHER) next to what the arm
  expected, on every arm and whether or not the case passes.
- Knob-off is unchanged and the pull build is untouched: every new branch is
  #if MOBILEGL_PIPE_PUSH, and symbol_report.py --threshold 0 against the pre-P2 baseline
  still reports 0 added / 0 removed / 0 renamed and the same four resized symbols
  (RenderState::RenderState, SetCapability, IsCapabilityEnabled, _GLOBAL__sub_I_DirectGLES.cpp).
This commit is contained in:
2026-09-08 00:19:39 -04:00
parent 2d690754dd
commit 55d2af9bd1
6 changed files with 231 additions and 69 deletions
+25 -4
View File
@@ -824,10 +824,18 @@ gtest_discover_tests(MobileGLIntegrationTest
# block: a ctest ENVIRONMENT property REPLACES the job environment for the names it lists, so an
# entry naming only its own knobs would lose the EGL vendor and Vulkan ICD pinning.
#
# The AbaControl arm is DirectVulkan only. The knob reverts two DirectVulkan guards
# (VertexInputStateFactory::ComputeHash's key and LookupVaoDrawMemo's lifetimeId compare); it
# steers nothing on DirectGLES, and a lane that configured it there would be a permanent skip
# claiming to be a control.
# The AbaControl arm is DirectVulkan only. The knob defeats the object-identity half of
# DirectVulkan's vertex-input memo keys (VertexInputStateFactory::ComputeHash, its per-VAO memo
# table, and LookupVaoDrawMemo); it steers nothing on DirectGLES, and a lane that configured it
# there would be a permanent skip claiming to be a control.
#
# It gets TWO lanes, because there are two arms and the control has to cover the one P2 SHIPS.
# `AbaControl` is D18's lane verbatim (MOBILEGL_PIPE_PUSH=0, the pre-handle arm) and defeats the
# lifetime-id/address guards; `AbaControlHandles` runs the handle arm (MOBILEGL_PIPE_LEGACY_MEMOS=0,
# the default push mask) and defeats the {slot, gen} GENERATION, which is what makes the re-keyed
# memos ABA-safe. With only the first lane the control says nothing at all about the re-key: the
# handle arm is not executed under MOBILEGL_PIPE_PUSH=0, so every guard it would have to defeat is
# in another branch.
#
# The two PUSH-ONLY knobs of those arms are set only in a push build, and the lane NAMES are
# unaffected by that (an ENVIRONMENT property is not part of a test's name, so G2 still sees the
@@ -860,6 +868,10 @@ mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_ABA_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=aba" "MOBILEGL_PIPE_PUSH=0"
${MGL_ITEST_ABA_ARM_KNOBS}
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
mgl_itest_join_environment(MGL_ITEST_VULKAN_HANDLE_ABA_HANDLES_ENVIRONMENT
"MOBILEGL_BACKEND_TYPE=DirectVulkan" "MGITEST_HANDLE_ARM=aba"
${MGL_ITEST_HANDLES_ARM_KNOBS} ${MGL_ITEST_ABA_ARM_KNOBS}
${MGL_ITEST_CAPABILITY_ENV} ${MGL_ITEST_VULKAN_ENV})
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectGLES.HandleRecycle.Handles."
@@ -906,6 +918,15 @@ gtest_discover_tests(MobileGLIntegrationTest
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_HANDLE_ABA_ENVIRONMENT}"
)
gtest_discover_tests(MobileGLIntegrationTest
TEST_PREFIX "DirectVulkan.HandleRecycle.AbaControlHandles."
TEST_FILTER "HandleRecycleScenario.*"
DISCOVERY_TIMEOUT 30
PROPERTIES
LABELS integration-gpu
TIMEOUT ${MGL_ITEST_TIMEOUT}
ENVIRONMENT "${MGL_ITEST_VULKAN_HANDLE_ABA_HANDLES_ENVIRONMENT}"
)
# --- G12: the CSO content-addressing negative control ---------------------------------
#