-
Notifications
You must be signed in to change notification settings - Fork 3
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
Possible soundness issue #14
Comments
Hello, what you describe is why self-ref cannot currently be done safely in rust. However, soundness is possible. In this crate the trick is the |
I know, I (in my own code base) and ouroboros both happily relied on this behavior until recently. However, the issue thread I linked to states that this is not enough; AFAICT, the mere fact that there is a &'static [u8] in there is a possible soundness issue. This is because a borrow that is passed into a function may not, even if it is encapsulated within a struct, dangle during the scope of said function. |
I had to do some more checking around, but here's a more detailed explanation: when an OwnedFace is passed into a function, the internal &'static [u8] inside the RawFace inside the Face inside the OwnedFace may reasonably be retagged (my understanding is that this currently does not happen but may change at any time in the future; one should try running this through Miri with -Zmiri-retag-fields=all, but I am not currently able to do that, sorry). If it is retagged, it would then be protected equivalently to a reference being passed into the function directly, meaning it has to be valid when the function returns (at which point the OwnedFace and the Vec inside it have been dropped, invalidating the borrow). See also: rust-lang/miri#2844 |
Thanks for expanding, I don't quite see how this applies to I'm not familiar with using miri, but I ran Perhaps we should add a miri run to the CI? |
In my current understanding of things, because the However, while looking at the code I did notice that struct SelfRefVecFace {
data: Vec<u8>,
face: Option<ttf_parser::Face<'static>>,
_pin: PhantomPinned,
} IMO wrapping in Alternatively, using |
Yikes. I somehow completely glossed over this in my "code review" yesterday before I decided to open this issue. That's embarrassing, that should indeed be fine then. My apologies @ alexheretic, I should stop opening GitHub issues past 10 pm 😓 That being said...
We don't actually need a MD because Face is already in an Option. We could just set that to None in Drop::drop to explicitly drop the face first before the storage gets dropped. Is a MD clearer? Maybe?
I personally think it makes more sense for us to use an MU than a Box given the discussion in #4. However, perhaps we should hold off on this (or any other) change until we can get a clearer picture of what exactly we need to guarantee fields don't get retagged. See also someguynamedjosh/ouroboros#88 (comment) |
Thanks for investigating. Let me know how you like #15 for ensuring drop order. |
someguynamedjosh/ouroboros#88
This crate, like
ouroboros
, uses a fake'static
to implement the self-referentialFace
. While I am not at all certain, my first-impression understanding based on theouroboros
issue linked above is that this is potentially unsound (as in, the compiler is free to generate UB) because ifOwnedFace
were to be passed into a function, the&'static [u8]
(stored insideFace<'static>
) would be invalidated at the end of function when theVec
is dropped.The text was updated successfully, but these errors were encountered: