Rust API for functions whose arguments may alias

The gmp library has low-level functions such as mpn_sub_n that take input pointers and an output pointer. In C these can alias (with some caveats), so you could call, e.g., mpn_sub_n(rp, ap, rp, n). This is of course forbidden with &mut references in Rust, so if we were wrapping this in Rust we might have several functions that call mpn_sub_n. How would we express an API like this in idiomatic Rust? Are there recommended names for the "tied" version of the functions where an input and output parameter are the same? How is this typically handled?

Raw pointers in Rust are allowed to alias, even *mut T, so you would probably declare such functions by simply transliterating their signature using raw pointers.

You could also use &Cell<xxx> so that Rust will help you with lifetimes. (and it should be ffi safe, so you can use it for the parameter(s) in the extern declaration)

2 Likes

This is really slick. But can you have overlapping Cell<[T]> instances? For gmp in particular arguments are allowed to coincide, but not otherwise overlap.

My question is more about how to make a safe and
idiomatic Rust API. Would you need several functions

fn sub(&mut [u64], &[u64], &[u64]) -> u64
fn sub_from(&mut [u64], &[u64]) -> u64

etc? How is this problem typically solved?

1 Like

Yes, &[Cell<T>] arrays may overlap. See e.g. this.

1 Like

It's possible to create partially overlapping but non-identical &Cell<[T]> instances by transmuting to a slice of cells, subslicing, and then transmuting back to a cell of slice. Immutable references to any type are always allowed to alias.

In idiomatic Rust, you typically wouldn't allow, encourage, or anticipate mutable aliasing.

Right, so wrapping mpn_sub_n as

fn sub(rp: &Cell<[u64]>, s1p: &Cell<[u64]>, s2p: &Cell<[u64]>) -> u64

although tempting, doesn't work. How do we typically deal with this? With several functions that all call mpn_sub_n under the hood with every possible legal combination of aliasing arguments?

Is there a good example of a crate that wraps a C API like this safely? (Not necessarily wrapping gmp---IIRC rug doesn't wrap the mpn layer).

I don't know of any wrapper crates trying to address this issue.

Again, I think there are actually two problems. The first one is idiomatically wrapping the functions, for which the solution is simply to forbid mutable aliasing, either by specifying references of appropriate (im)mutability in input and output parameter positions, or by simply always allocating the output parameter inside the wrapper and returning it by value.

The other problem is verifying that two slices either alias completely or are disjoint completely, but do not overlap partially. I don't think this can be verified at compile time, although you can definitely write a runtime assertion for it.

Note that this is unsound when combined with a way to go from a cell of slice to a cell of array (i.e. from &Cell<[T]> to &Cell<[T; N]>). This happens due to Cell::swap assuming that two &Cell<T> never partially overlap.

Since the conversion &Cell<[T]> to &Cell<[T; N]> seems reasonable and the conversion from &[Cell<T>; N] to &Cell<[T; N]> is already unsound (see Cell::swap assumes Cells never overlap · Issue #80778 · rust-lang/rust · GitHub), I would say that the conversion from &[Cell<T>] to &Cell<[T]> (and thus your proposal) should also be considered unsound.

Isn't that a bug in swap though? The whole point of cell-like types is to allow shared mutability. Obviously, since arrays and slices exist, sharing them means partial overlaps are 100% expected. Any correct implementation of Cell::swap() should therefore make sure to support these cases (eg. by memmove()ing rather than memcpy()ing).

It was probably a mistake to stabilize swap, yes. Its existence makes it unsound for partially overlapping cells to exist.

(It's ok for them to overlap if they are slices because swap doesn't work with unsized types.)

1 Like

Maybe we can use #[deprecated_safe]? Or just panic...

Well, there's currently no safe way to create partially overlapping cells. I believe one suggestion is to have it panic if the two cells partially overlap.

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.