NVIDIA / NVIDIA/cuda-python

Pool-backed MemoryResource buffers bypass overridden deallocate() methods

Aperta
#2,615 3 commenti 0 reazioni 1 assegnatario Vedi su GitHub

@Andy-Jost ci sta già lavorando.

Dal 13/8/2026.

bug cuda.core
Lingua principale
Cython
Stelle
3.4k
Fork
329
Merge medio
1g 21h
PR unite (30g)
113

Descrizione

Summary

Buffers allocated by pool-backed memory resources are freed directly by their C++ DevicePtrHandle deleter. Their associated memory resource's deallocate() method is never called.

This makes deallocation behavior inconsistent and prevents subclasses of DeviceMemoryResource, PinnedMemoryResource, and ManagedMemoryResource from observing or customizing teardown.

Reproducer

from cuda.core import Device, DeviceMemoryResource

calls = []


class RecordingMemoryResource(DeviceMemoryResource):
    def deallocate(self, ptr, size, *, stream):
        calls.append((ptr, size, stream))
        return super().deallocate(ptr, size, stream=stream)


device = Device()
device.set_current()

mr = RecordingMemoryResource(device)
buf = mr.allocate(1024, stream=device.default_stream)

assert buf.memory_resource is mr
buf.close()

assert len(calls) == 1  # Fails: calls is empty

The allocation is freed, but directly through the C++ handle rather than through RecordingMemoryResource.deallocate().

Inconsistent behavior

The behavior depends on how the Buffer was constructed:

  • mr.allocate(...) uses a directly owning C++ handle and bypasses mr.deallocate().
  • Buffer.from_handle(..., mr=mr) records the MR as the owner and dispatches teardown through mr.deallocate().

Consequently, the same memory resource subclass has two different deallocation models.

Callback-backed resources such as LegacyPinnedMemoryResource also dispatch through mr.deallocate(), making the behavior inconsistent between built-in resource implementations.

Expected behavior

If concrete memory resources are supported as subclass bases, an overridden deallocate() should be honored for buffers allocated by the subclass.

This is useful for accounting, tracing, validation, failure injection, and custom resource policies—not only test instrumentation.

If concrete memory resources are intentionally not subclassable, that restriction should instead be explicit and enforced.

Implementation considerations

The current direct C++ path has important properties that should be preserved:

  • It retains the memory-pool handle for the allocation lifetime.
  • It can free without executing Python during interpreter shutdown.
  • It stores the stream/context recipe needed for safe deferred teardown.

A fix may therefore require a callback-capable pool allocation handle that retains the pool while dispatching through the Python MR, or a fast path for exact built-in types with callback dispatch for subclasses.

GraphMemoryResource, which also creates directly owning handles, should be audited for the same behavior.

Related

  • #1989 — inconsistent lifetime management across from_handle / from_* APIs
  • #2526 — capture complete Buffer deallocation recipe at creation

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.