Skip to content

Possible to interleave &mut and & safely? #562

Open
@joshlf

Description

@joshlf

I'm working on a linked list implementation for an embedded kernel. We have the following Thread structure, which will be a member of a list:

struct Node<T> {
    next: Option<NonNull<Node<T>>>,
    prev: Option<NonNull<Node<T>>>,
    t: T,
}

struct Thread {
    stack: [u8; STACK_SIZE],
    id: u32,
    ...
}

The stack is the thread's stack, which will be used to hold arbitrary Rust values, which might include &mut references to other values in the stack (i.e., it might be self-referential). (While pinning is obviously a concern, that's not what this issue is about.)

In addition to self-references in the stack, we also need to be able to inspect other fields in Thread from inside the scheduler.

Here's an example - possibly problematic - sequence of events:

  1. Some code runs in the thread which writes a &mut reference to the stack that also refers to the stack.
  2. The thread yields control, which hands control over to the scheduler
  3. The scheduler obtains a &Node<Thread> reference to the currently-running thread and reads its id field

While, in (3), we haven't read data from stack, I presume that it's still considered UB to have a &Node<Thread> while other &mut references exist which point into the stack, which overlaps with the referent of the &Node<Thread>?

My first thought was to just wrap the whole thing in UnsafeCell so that the Node API doesn't provide &Threads, but instead provides &UnsafeCell<Thread>s. But IIUC that doesn't solve the problem - it's still illegal to have &UnsafeCell<T> and &mut T overlap.

My next thought was to just use raw pointers and never synthesize & references.

Concretely, my questions are the following. All of them are in the context of &mut references existing which refer to stack.

  • Given a NonNull<Node<Thread>>, is it sound to perform pointer arithmetic to obtain a NonNull<u32> and dereference it? Specifically, is it problematic that the original NonNull<Node<Thread>> refers to the whole Thread, including the stack?
  • Is there any way to provide a non-raw-pointer API which provides access to the inner T in a Node<T> which would play nicely with this use case?

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