Repository navigation
[BUG]: CUtensorMap owned storage does not honor required alignment #3181
Description
Type of Bug
Something else: backing-storage alignment does not meet the C type's declared requirement.
Component
cuda.bindings
Describe the bug
I discovered this alignment issue while reviewing #3095, which adds the _v2.driver API. Checking the existing cuda.bindings.driver.CUtensorMap implementation showed that the same allocation pattern is already present in released versions.
The wrapper embeds the C descriptor inside a Python object and does not explicitly enforce its alignment. The required alignment depends on the CUDA header version: the wrapper documentation specifies 128 bytes in v13.4.4 and 64 bytes in v12.9.9.
Released implementations with this allocation pattern
- v13.4.4:
CUtensorMap_st.__cinit__points_pvt_ptrat the inline_pvt_val; its docstring specifies 128-byte alignment. - v12.9.9: the same constructor pattern is present; its docstring specifies 64-byte alignment.
These are concrete released examples confirmed by source inspection, not a claim about the first affected release. PR #3095 uses equivalent inline storage for _v2.driver.TensorMap. This issue tracks the shared allocation limitation separately from that PR.
In the legacy wrapper, default construction points _pvt_ptr at &self._pvt_val:
The C compiler can align a member's offset within the containing object, but CPython's object allocator does not guarantee a 128-byte-aligned base address. Consequently, the descriptor's actual address need not meet the C type's alignment requirement.
How to Reproduce
Inspect the backing addresses of existing legacy API objects, for example with cuda.bindings v13.4.4; no GPU or CUDA API call is needed:
from cuda.bindings import driver
# Keep the objects alive so the allocator cannot simply reuse one address.
maps = [driver.CUtensorMap() for _ in range(200)]
addresses = [int(m.getPtr()) for m in maps]
print("address residues modulo 128:", sorted({p % 128 for p in addresses}))
print("address residues modulo 64:", sorted({p % 64 for p in addresses}))
assert all(p % 128 == 0 for p in addresses)For v12.9.9, check modulo 64 instead, matching that version's documented requirement.
The assertion can fail because alignment stronger than the Python allocator's guarantee occurs only incidentally. Exact residues depend on the Python build and allocator; a run that happens to return aligned addresses does not establish a guarantee.
Validation: source inspection confirms the inline allocation in both versions. A separately compiled Cython reproduction using the actual CUDA header and the new wrapper's class layout produced descriptor addresses with residues 0, 16, 32, and 48 modulo 64. The legacy-API script above is provided for validation against an installed build; it was not run as part of that reproduction.
Expected behavior
Owned tensor-map storage should honor alignof(CUtensorMap) (128 bytes in the inspected header), including storage used internally by encoding wrappers. Regression tests should check the pointer alignment directly, not only whether encoding succeeds.
Observed impact and scope
No CUDA encoding failure or protected-memory fault has been demonstrated here. Existing tensor-map tests do not establish a storage-alignment guarantee, and successful encoding alone does not prove that guarantee. This report concerns meeting the documented alignment contract; it should not claim that tensor-map APIs are generally unusable or that #3095 newly breaks them.
Possible fix
Provide explicitly aligned owned storage for tensor-map wrappers, with matching deallocation and support for copy-producing construction paths. The generator's external-storage mode currently uses ordinary allocation, so selecting it alone does not guarantee extended alignment.
A broader generator enhancement could support alignment-aware allocation for AUTO_LOWPP_CLASS; a dedicated tensor-map allocation path is another option. Borrowing an externally aligned pointer is already possible, but does not fix wrappers that construct their output object internally, such as the new tensor_map_encode_tiled.
Activity
[-][BUG]: Struct-valued setters in _v2.driver bypass read-only destination protection[/-][+][BUG]: Existing CUtensorMap backing storage does not guarantee required alignment[/+][-][BUG]: Existing CUtensorMap backing storage does not guarantee required alignment[/-][+][BUG]: CUtensorMap owned storage does not honor required alignment[/+]mdboom commentedon Oct 21, 2026
I think the fix here is:
alignmentPyObject, when present, this will force use of generating classes in "external" modealloc_align/memsetrather thancallocto align to the correct amountfrom_ptrwill be updated similarly in the copy case, and in the non-copy case will raise an exception if the passed-in pointer is not aligned correctly.