You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Yanking 0.17.0 due to use-after-free unsoundness #1531
The excellent @sarah-quinones has pointed out to me that the current design of ArrayRef is unsound and can cause use-after-free without the use of any unsafe. She has also provided a feasible path forward for a redesign that should be relatively small. However, I feel obliged to yank 0.17.0 to avoid leaving use-after-free inside the core of the library.
My apologies to everyone, especially those contributors whose contributions will be temporarily unavailable. I will work as fast as I can to get a new version up, which I will be submitting to some rigorous review before its release (0.17.1). I appreciate everybody's patience as I work through this.
Update, which I'll try to be providing frequently: the initial suggestion seems to be working well, and has precluded the original use-after-free bug. Further QA will be happening over the next few days.
Reacted by Raoul Luqué, Bhattarapong Somwong, amfaber, Zach Krzyzanowski, NewBornRustacean, Enes and Jan-Kristian Mathisen
Update: I've also now implemented a modified cousin of the initial fix that also seems to be working.
I'm planning on writing as much as I can about this issue when I'm able to, including some detailed technical notes that can hopefully help others avoid the same mistake. For now, however, here's the skinny: the reference types have to be unsized, and they were sized. I don't think there's any way around it; if they're sized, Rust thinks that it can see the entire type on the stack or heap and will happily do things like std::men::swap on it.
There are two ways to accomplish this. Sarah's original suggestion was to use a trait object, which is a DST. That appeared to have "worked", at least insomuch that the original unsound example no longer compiles and all tests still run. The problem here is that it would embed the pointer to the data behind a vtable, which I'm worried would significantly harm performance.
The second approach is to use a type whose final member is itself a DST; in this case, I've opted for a slice. This also appears to have "worked", making the unsound example not compile and all tests still run. I think this is probably what I'll use, since it's more transparent to the compiler.
note: my suggestion was to use a market trait as the dyn trait type.
e.g. you would have an unsafe market trait that promises the type has the layout of an array (ptr, shape, stride), and then you don't have to go through an indirect call. you can just take the &mut dyn ISwearThisIsAnArray and reinterpret it as a pointer to ArrayView[Mut] by casting it to a thin pointer to discard the vtable
@sarah-quinonesthat PR is now ready for review. I've taken a different approach from your suggestion; I detail at the end of the PR description why I opted for something different. Thank you so much for all of your help with this process!
Activity
akern40 commentedon Oct 16, 2025
Update, which I'll try to be providing frequently: the initial suggestion seems to be working well, and has precluded the original use-after-free bug. Further QA will be happening over the next few days.
akern40 commentedon Oct 17, 2025
Update: I've also now implemented a modified cousin of the initial fix that also seems to be working.
I'm planning on writing as much as I can about this issue when I'm able to, including some detailed technical notes that can hopefully help others avoid the same mistake. For now, however, here's the skinny: the reference types have to be unsized, and they were sized. I don't think there's any way around it; if they're sized, Rust thinks that it can see the entire type on the stack or heap and will happily do things like
std::men::swapon it.There are two ways to accomplish this. Sarah's original suggestion was to use a trait object, which is a DST. That appeared to have "worked", at least insomuch that the original unsound example no longer compiles and all tests still run. The problem here is that it would embed the pointer to the data behind a vtable, which I'm worried would significantly harm performance.
The second approach is to use a type whose final member is itself a DST; in this case, I've opted for a slice. This also appears to have "worked", making the unsound example not compile and all tests still run. I think this is probably what I'll use, since it's more transparent to the compiler.
sarah-quinones commentedon Oct 17, 2025
note: my suggestion was to use a market trait as the dyn trait type.
e.g. you would have an unsafe market trait that promises the type has the layout of an array (ptr, shape, stride), and then you don't have to go through an indirect call. you can just take the &mut dyn ISwearThisIsAnArray and reinterpret it as a pointer to ArrayView[Mut] by casting it to a thin pointer to discard the vtable
akern40 commentedon Oct 19, 2025
@sarah-quinones that PR is now ready for review. I've taken a different approach from your suggestion; I detail at the end of the PR description why I opted for something different. Thank you so much for all of your help with this process!