-
Couldn't load subscription status.
- Fork 61
Description
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:
- Some code runs in the thread which writes a
&mutreference to the stack that also refers to the stack. - The thread yields control, which hands control over to the scheduler
- The scheduler obtains a
&Node<Thread>reference to the currently-running thread and reads itsidfield
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 aNonNull<u32>and dereference it? Specifically, is it problematic that the originalNonNull<Node<Thread>>refers to the wholeThread, including thestack? - Is there any way to provide a non-raw-pointer API which provides access to the inner
Tin aNode<T>which would play nicely with this use case?