Skip to content

cuda.core: reject operations on closed resource objects #2627

Description

@Andy-Jost

Summary

Add a consistent closed-state contract to cuda.core resources. Closed objects must fail before a NULL native handle reaches CUDA.

Problem

Several cuda.core objects reset a shared native handle in close(), but their methods do not check that state. This can cause late CUDA errors, stale metadata, or invalid native access. Streams are the highest risk because CUDA can interpret a NULL CUstream as the default stream. Work that targets a closed stream can therefore run on the wrong stream instead of failing.

The same risk exists in event operations, buffer operations, memory pools, graph resources, compiler resources, texture resources, and cross-object conversion paths.

Required behavior

  • Add __bool__ where an object has a clear open or closed state.
  • Test the shared handle state, not the numeric CUDA handle. An open Stream.from_handle(0) and an open zero-size Buffer must remain true.
  • Raise RuntimeError("<Type> has been closed") before an active operation uses a closed resource.
  • Keep repeated close(), handle inspection, and repr() safe.
  • Keep current equality and hash behavior. A separate change can address mutable hash or closed-object equality rules.
  • Make Stream.close() a no-op for CUDA default-stream tokens. These tokens use process-wide singleton wrappers and own no CUDA resource.
  • Keep memory-pool deallocate() available after pool close so that outstanding buffers can complete cleanup.

Scope

Apply the contract to these resources and their acceptance paths:

  • Stream, Event, Buffer, and ManagedBuffer.
  • Context, Program, and Linker.
  • DeviceMemoryResource, PinnedMemoryResource, and ManagedMemoryResource.
  • GraphBuilder, executable Graph, destroyed GraphNode objects, and invalid child GraphDefinition views.
  • OpaqueArray, MipmappedArray, TextureObject, SurfaceObject, and GraphicsResource.
  • IPCAllocationHandle.

Update central conversion and acceptance paths. This includes Stream_accept, stream protocol conversion, event use in streams and graphs, buffer use in copy and managed-memory operations, DLPack, IPC, memory views, kernel arguments, virtual memory, and texture descriptors.

A valid virtual graph entry node and a destroyed graph node both have a NULL CUgraphNode. Add explicit state that distinguishes them. Reject destroyed nodes in graph construction and adjacency changes. Reject invalid child graph views in graph queries, embedding, instantiation, and updates.

GraphMemoryResource.close() and ProgramCacheResource.close() are out of scope because they do not create a closed native-resource state.

Buffer deallocation stream

Buffer.set_deallocation_stream() and Buffer.close(stream=...) must reject a closed Stream or closed GraphBuilder. A failed update must leave the current deallocation stream unchanged. A closed Buffer must remain rejected as specified in #2600 and #2602.

Acceptance criteria

  • Each covered resource reports the correct Boolean state before and after close or invalidation.
  • No covered active operation passes a released handle to CUDA.
  • Stream_accept rejects every closed stream source.
  • Closed events are rejected by stream and graph event operations.
  • Closed buffers are rejected by direct methods and indirect consumers.
  • Closed memory pools reject new work but still permit required deallocation.
  • Destroyed graph nodes and invalid child graphs fail with a clear runtime error.
  • CUDA default-stream singleton wrappers remain usable after close().
  • Tests cover Boolean state, safe object protocols, idempotent cleanup, active-method guards, conversion paths, and deallocation-stream failure atomicity.

Related

Metadata

Metadata

Assignees

Labels

P0High priority - Must do!bugSomething isn't workingcuda.coreEverything related to the cuda.core module

Type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions