Description
I ran into an error while experimenting with round-robin thread scheduling, and it raised the question for me of whether protectors should only be considered active from the context of the same thread that they were created on, or whether protectors should be considered active regardless of the thread that is performing the access. This came up with an atomically reference counted data structure, and I don't see any way of fundamentally avoiding the issue by making changes to the data structure's code. If we use std atomics, then each thread that decrements a refcount will hold a shared reference inside the allocation, and that reference could be on the stack arbitrarily long after decrementing, if the thread is preempted. Then, other threads would be able to see the decrement and free the allocation, while that first thread's reference still exists. I wrote a minimized test case that can reproduce the error I encountered, regardless of thread scheduling policy.
I'm not sure which way this should go. On the one hand, I could read references to "the call stack" as referring to the current call stack, in which case we could make the active protector set per-thread in Miri and this would go away. On the other hand, this would open the possibility of a dangling reference in a local, and I'm not sure whether that's allowed, even if it's not accessed once it's dangling. Perhaps the deallocation check could be made more permissive while leaving access checks as they are? Alternately, what if Arc
and similar data structures require new APIs that take *const AtomicUsize
, for cases where the pointer could become dangling right after the synchronization operation? I'd appreciate your thoughts; let me know if this should go in the UCG repo.