-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shared and Unique slices and ZST #168
Comments
The way I understood it, the key question we debated was whether this is a safe function: fn arbitrary_blowup<'a, T>(slice: &'a [T], length: usize) -> &'a [T] {
assert!(core::mem::size_of::<T>() == 0);
assert!(!slice.is_empty());
unsafe {
core::slice::from_raw_parts(slice.as_ptr(), length);
}
} By "safe" I mean "can be called by arbitrary safe code without causing UB". I originally thought it was not, but now I am convinced it is. @gnzlbg asks
The thing is, |
Does the index also not matter for If it does matter, how does that work with |
Hmm, I guess that because this is just getting you new references to the ZSTs, it's safe, since you could always have gotten new references by copying the references. |
First, are we in agreement for shared slices? That the function is safe? For mutable slices, no, the function is not sound. I wrote this down more than a year ago in some discussion but it seems the same questions will come up again and again, and of course I cannot find my write-up, so here you go. Basically @scottmcm gave the answer away: you could have copied the shared refs. You cannot do that with mutable refs. So imagine a type of which you can only get one instance: pub mod one {
//! A value of which you can only have one.
use std::sync::atomic::{AtomicBool, Ordering};
static USED: AtomicBool = AtomicBool::new(false);
pub struct OnlyOne(()); // private field to make constructor private
impl OnlyOne {
pub fn new() -> Self {
let used_before = USED.compare_and_swap(false, true, Ordering::Relaxed);
if used_before {
panic!("Cannot get more than one of these!");
}
OnlyOne(())
}
pub fn check(_x1: &mut Self, _x2: &mut Self) {
// We could cause UB here if we wanted, and still have a safe API.
unreachable!()
}
}
} With let one = &mut [OnlyOne::new()];
let two = arbitrary_blowup(one, 2);
let (left, right) = two.split_at_mut(1);
OnlyOne::check(left, right); // oops! |
Okay, sure, but also I wasn't talking about except how does split_at_mut interact with &mut aliasing? When you do split_at_mut it does an add internally, which adds 0 bytes because size is zero, so you end up with two |
First of all, sorry for taking the other thread too far. It started off as what I perceived to be closely related to the thread title and then diverged to something entirely different. And I realize now that I should have forked probably very promptly after the first answer when it was at least clear in hindsight that it would widen the scope considerably. I'll try not to repeat this. Now, it is not possbily to conclusively proof dynamically that two non-mutable ZST slices do not 'alias' each other. They could have been created from either overlapping ranges or from disjunct ranges and would still look alike. But at the same time, two |
The only concern we have in this thread is about "safety invariants". When you have two Concatenation is fine, as is |
@RalfJung I made this thread to ask further questions, as you requested in the other thread, and then I repeated my aliasing question one time because you ignored it the first time. After you said, just there, that there's no aliasing for ZST as if it was somehow obvious (hint: it's not) I was able to find a year old issue about it in the previous repo: rust-lang/rust-memory-model#44, but this is not covered at all in the UCG and the Rustonomicon gives a very hand-wavey definition as well. You can't expect people to know what the book will say before you've written the book about it. |
For As for not checking the pointer, what if a ZST is designed such that pointers to it encode information in the pointer value itself? |
As explained in the issue Ralf mentioned, general concat is not safe because even if two slices fall next to each other in memory they must also be part of the same allocation to be combined, which you in general have no way of knowing (if all slices are known to be out of the same vec or something it can work out, but you need that extra info). I updated the first post of the thread to help note that difficulty. I don't know about the pointer encode part. |
Sorry. I didn't mean to ignore it. I also meant my post more as an answer to your OP above than any specific comment below, when I realized that this is a point I forgot to make last night (as I was falling asleep...).
Seems I have a hard time figuring out what is obvious and what is not. :/
Good find!
The issue is I have no idea where to put this. I (tried to) expressed my frustration about that fact above. I was not frustrated by you and I am sorry if I came across as such!
Not sure about concat, but I am sure the function presented here is safe. No need to make the question more complicated. :) |
@Lokathor Now that aliasing is defined in the glossary, what is left to be discussed here? Are there open questions, things that should be put into the UCG document? |
naw we can close this up and call it good for now. reminder to others who find this later: people can always feel free to start new issues if there are further questions not answered here. |
At what is currently the bottom of #93 there were some interesting questions raised, but it was offtopic to that issue so here's a new one.
Big Question: How exactly do ZST interact with slices?
There's obviously a lot of sub-questions involved here.
So the immediate questions to ask ourselves are:
The text was updated successfully, but these errors were encountered: