big_gie
big_gie

Reputation: 3017

In Rust <1.84, is it possible/sound to join two subslices that originated from the same original slice?

I have a type that stores a slice, for example:

struct S<'a> {
    slice: &'a [u8],
}

I am trying to write code that will merge two of these structs. Now obviously this should only succeed if the two slices are subslices of the original data. I believe this can be checked with pointers: make sure that the ranges "in pointer space" (i.e. [pointer, pointer+length]) of each slices overlap. If this is the case, then both slices are views into the same original memory location.

After having done this check, I use let new_slice = unsafe { core::slice::from_raw_parts(lower_ptr, new_length_elements) }; to reconstruct the slice. This sounds fine, including the unit tests making sure this works as expected, but Miri complains:

error: Undefined Behavior: trying to retag from <718383> for SharedReadOnly permission at alloc
486[0x14], but that tag does not exist in the borrow stack for this location
    --> ~/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/raw.rs:138:9                                             |
138  |         &*ptr::slice_from_raw_parts(data, len)
     |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     |         |
     |         trying to retag from <718383> for SharedReadOnly permission at alloc486[0x14], but that tag does not exist in the borrow stack for this location
     |         this error occurs as part of retag at alloc486[0x8..0x18]
     |
     = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental
     = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information
help: <718383> was created by a SharedReadOnly retag at offsets [0x8..0x14]
    --> example/src/lib.rs:229:24
     |
229  |         let lower_ptr = self.slice.as_ptr();
     |                        ^^^^^^^^^^^^^^^^^^^
     = note: BACKTRACE (of the first span) on thread `tests::merge`:
     = note: inside `std::slice::from_raw_parts::<'_, u32>` at ~/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/core/src/slice/raw.rs:138:9: 138:47

I'm not sure I fully understand the error.

Should it be possible to rebuild a slice from two subslices that we taken from a single memory location? How should it be done so that Miri doesn't complain?

Upvotes: 0

Views: 40

Answers (0)

Related Questions