[BUG] Rust: ManagedTensor borrows host ndarray shape storage; index outliving the host array reads a dangling pointer at Drop
Nobody has claimed this yet.
- Dominant language
- Cuda
- Stars
- 854
- Forks
- 236
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 62
Description
Describe the bug
In the Rust crate, ManagedTensor::from(&ndarray) stores arr.shape().as_ptr() — a pointer into the host ndarray's owned dimension storage — and .to_device() copies the DLTensor struct including that borrowed shape pointer. Index types that retain a non-owning device view of their build dataset (observed with brute_force::Index, which keeps _dataset) therefore alias the host array's dims. If the host Array2 is dropped (or moved out of scope) while the index is alive, the index's Drop reads the dangling shape pointer — observed as SIGABRT via multiply-overflow in dlpack.rs::dl_tensor_bytes.
Steps/Code to reproduce bug
let index = {
let dataset: ndarray::Array2<f32> = /* ... */;
let dev = ManagedTensor::from(&dataset).to_device(&res)?;
brute_force::Index::build(&res, ¶ms, &dev)?
// dataset dropped here; index._dataset.shape now dangles
};
// index.drop() -> dl_tensor_bytes reads garbage dims -> SIGABRT
Nothing in the type system prevents this; it compiles cleanly.
Expected behavior
Either the borrow is impossible to outlive, or the tensor owns its shape.
Recommended fix
Make ManagedTensor own its shape/strides storage: copy the dims into an internal Box<[i64]> at construction and point DLTensor.shape at that owned buffer (likewise strides). This is API-compatible, costs a few words per tensor, and removes the hazard for every index type at once. The stricter alternative — threading a lifetime parameter (ManagedTensor<'a> with PhantomData<&'a ()>) — is sound but viral across every index API signature, so the owned-shape approach seems the better fit. We hit this while adding serialize bindings (#2231) and worked around it test-side with drop ordering; happy to submit the owned-shape fix as a PR if the approach sounds right.
Environment details
Rust crate at main (78135be4), conda libcuvs 26.06, CUDA 13.1, RTX 4000.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Trace ManagedTensor::from(&ndarray) through .to_device() and brute_force::Index::build, then inspect dlpack.rs::dl_tensor_bytes. Verify how shape and strides storage are retained across device copies and reproduce the index drop after the host array leaves scope. Done means the tensor owns the relevant storage and the dangling-pointer failure no longer occurs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 52/100