Found while repairing LTX-2.5 phases L7/L8 (#435, PR #437). Not an LTX defect — it is a latent fault in a shared hot path that LTX merely became the first caller to reach.
The defect
vllm::Pool() is a process-wide singleton whose free list is keyed by size class only. The device is not part of the key. So a block allocated with cudaMalloc for a CUDA arm is returned to the pool and then handed straight to a CPU-backend DBuf on the next allocation of the same size class, which copies into it with a host memcpy.
Symptom
test_ltx2_device SIGSEGV on GB10:
__memcpy_sve <- UploadStream <- PrepareStreamDev
8 cases run, 1 failed, 5 never reached — this project's "changed COUNT = RED" signature.
compute-sanitizer reports 0 device errors, which is the tell: the fault is host-side, dereferencing a device pointer from the CPU. A tool aimed at the GPU cannot see it.
Why it stayed hidden
It requires a bf16 CPU-backend device forward to run after a bf16 CUDA one in the same process. No test had ever done that. At f32 the two arms land in different size classes and never trade blocks, so the f32 gates could not reach it either.
That is spec §7.0(c) again (): a fixture that cannot enter the regime that discriminates. The bug is old; only the ordering is new.
Immediate mitigation (in the LTX repair, not a fix for this issue)
The CPU arm now runs under its own DevicePool via ActivePoolScope. That seam already exists for exactly this shape — AuxPool() is documented as existing because "two streams sharing one pool BREAKS" its reuse ordering. test_ltx2_device is back to 13/498 SUCCESS on the CPU backend.
That scopes one caller away from the hazard. It does not fix the pool.
What this issue wants
Put the device in the free-list key, so a block allocated on one device can never be handed to another. It is a shared hot path, so:
- it needs its own row, spec and red-first test;
- the test must be the ordering that exposes it (same size class, CUDA allocation freed, then a host-backend allocation), because nothing currently in the tree produces it;
- worth auditing whether any other caller mixes backends within a size class today, since the failure mode is a host dereference of a device pointer and would present as an unrelated segfault.
Blast radius, honestly stated
Unknown and worth establishing. Any code path that allocates on CUDA, frees, then allocates the same size class on a host backend in the same process is exposed. It has been latent long enough that nothing in the current suite triggers it, so "no failures today" is not evidence of safety — it is evidence that no test has produced the ordering.
Related: #449 (an instrument that could not see the defect class it existed to catch), .agents/specs/ltx-2-5.md §7.0.
🤖 Generated with Claude Code
Found while repairing LTX-2.5 phases L7/L8 (#435, PR #437). Not an LTX defect — it is a latent fault in a shared hot path that LTX merely became the first caller to reach.
The defect
vllm::Pool()is a process-wide singleton whose free list is keyed by size class only. The device is not part of the key. So a block allocated withcudaMallocfor a CUDA arm is returned to the pool and then handed straight to a CPU-backendDBufon the next allocation of the same size class, which copies into it with a hostmemcpy.Symptom
test_ltx2_deviceSIGSEGV on GB10:8 cases run, 1 failed, 5 never reached — this project's "changed COUNT = RED" signature.
compute-sanitizerreports 0 device errors, which is the tell: the fault is host-side, dereferencing a device pointer from the CPU. A tool aimed at the GPU cannot see it.Why it stayed hidden
It requires a bf16 CPU-backend device forward to run after a bf16 CUDA one in the same process. No test had ever done that. At f32 the two arms land in different size classes and never trade blocks, so the f32 gates could not reach it either.
That is spec §7.0(c) again (): a fixture that cannot enter the regime that discriminates. The bug is old; only the ordering is new.
Immediate mitigation (in the LTX repair, not a fix for this issue)
The CPU arm now runs under its own
DevicePoolviaActivePoolScope. That seam already exists for exactly this shape —AuxPool()is documented as existing because "two streams sharing one pool BREAKS" its reuse ordering.test_ltx2_deviceis back to 13/498 SUCCESS on the CPU backend.That scopes one caller away from the hazard. It does not fix the pool.
What this issue wants
Put the device in the free-list key, so a block allocated on one device can never be handed to another. It is a shared hot path, so:
Blast radius, honestly stated
Unknown and worth establishing. Any code path that allocates on CUDA, frees, then allocates the same size class on a host backend in the same process is exposed. It has been latent long enough that nothing in the current suite triggers it, so "no failures today" is not evidence of safety — it is evidence that no test has produced the ordering.
Related: #449 (an instrument that could not see the defect class it existed to catch),
.agents/specs/ltx-2-5.md§7.0.🤖 Generated with Claude Code