Skip to content

Yanking 0.17.0 due to use-after-free unsoundness #1531

Closed

Description

@akern40

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.

Activity

  1. akern40 commented on Oct 16, 2025

    @akern40
    CollaboratorAuthor

    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.

  2. akern40 commented on Oct 17, 2025

    @akern40
    CollaboratorAuthor

    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.

  3. sarah-quinones commented on Oct 17, 2025

    @sarah-quinones

    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

  4. akern40 commented on Oct 19, 2025

    @akern40
    CollaboratorAuthor

    @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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions