-
Notifications
You must be signed in to change notification settings - Fork 352
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
store futexes in per-allocation data rather than globally #3971
Conversation
100e5a5
to
442a5bc
Compare
☔ The latest upstream changes (presumably #3973) made this pull request unmergeable. Please resolve the merge conflicts. |
442a5bc
to
fc7eec2
Compare
☔ The latest upstream changes (presumably #3974) made this pull request unmergeable. Please resolve the merge conflicts. |
I don't mind declaring such cases Too Weird For Rust (or Miri). Same goes for reusing addresses; if someone comes up with an actual use case for these we can consider figuring it out then. But that seems unlikely. |
fc7eec2
to
ba11d43
Compare
Cc @m-ou-se who did the original implementation here and made it work on al (even dangling) addresses. |
The only thing that's important is that it doesn't segfault/crash/panic/do anything bad when calling futex_wake on a futex that no longer exists. So, something like: let b = Box::new(AtomicU32::new(0));
let p = b.as_ptr();
// ...
drop(b);
// ...
futex_wake(p, 1); // "use after free" is perfectly fine for futex_wake! This should just do nothing (or spuriously wake another futex, whatever). |
@@ -35,17 +35,6 @@ fn wake_nobody() { | |||
} | |||
} | |||
|
|||
fn wake_dangling() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should still work. At least parking_lot depends on "wake after free" to be acceptable.
Edit: or it should return -1 with errno set to EFAULT, treating deallocated memory as unmapped memory.
From parking_lot_core: // The thread data may have been freed at this point, but it doesn't
// matter since the syscall will just return EFAULT in that case.
let r = libc::syscall(
libc::SYS_futex,
self.futex,
libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG,
1,
); Note that the linux kernel returns EFAULT when the memory is unmapped. In most cases, memory freed by the global allocator is still mapped (so the kernel doesn't know it's deallocated), but it seems perfectly fine for miri to just always return EFAULT if the allocation is gone. |
Returning EFAULT would for the first time let a program "test" whether a given address is allocated. But maybe we should still do it. |
Yeah. It's more accurate to just return success if the memory is deallocated, without waking up anything. I don't think it matters much. |
ba11d43
to
b394f0d
Compare
Yeah I think I prefer that. EDIT: After thinking about it some more, I think I prefer the EFAULT variant. That makes it more likely that someone will file a bug report if this behavior for some reason doesn't work for them. |
d039db8
to
d300f7d
Compare
interpret: get_alloc_info: also return mutability This will be needed for rust-lang/miri#3971 This then tuned into a larger refactor where we introduce a new type for the `get_alloc_info` return data, and we move some code to methods on `GlobalAlloc` to avoid duplicating it between the validity check and `get_alloc_info`.
interpret: get_alloc_info: also return mutability This will be needed for rust-lang/miri#3971 This then tuned into a larger refactor where we introduce a new type for the `get_alloc_info` return data, and we move some code to methods on `GlobalAlloc` to avoid duplicating it between the validity check and `get_alloc_info`.
Rollup merge of rust-lang#132801 - RalfJung:alloc-mutability, r=oli-obk interpret: get_alloc_info: also return mutability This will be needed for rust-lang/miri#3971 This then tuned into a larger refactor where we introduce a new type for the `get_alloc_info` return data, and we move some code to methods on `GlobalAlloc` to avoid duplicating it between the validity check and `get_alloc_info`.
interpret: get_alloc_info: also return mutability This will be needed for rust-lang#3971 This then tuned into a larger refactor where we introduce a new type for the `get_alloc_info` return data, and we move some code to methods on `GlobalAlloc` to avoid duplicating it between the validity check and `get_alloc_info`.
d300f7d
to
f15350b
Compare
This comment has been minimized.
This comment has been minimized.
I've also changed the ordering of the read in |
3609e56
to
242aff9
Compare
242aff9
to
b9302f3
Compare
interpret: get_alloc_info: also return mutability This will be needed for rust-lang/miri#3971 This then tuned into a larger refactor where we introduce a new type for the `get_alloc_info` return data, and we move some code to methods on `GlobalAlloc` to avoid duplicating it between the validity check and `get_alloc_info`.
This is a change in behavior. We used to index futexes entirely on their absolute address, so they stuck around even if the allocation backing that address disappears -- in fact one could signal FUTEX_WAKE on unallocated memory. That works fine on Linux but is quite odd from a Rust AM perspective. It also means Miri has a leak, as some futex state never disappears.
So this PR attaches the futex to the "virtual" address inside an allocation, meaning it disappears when the allocation is freed. Strictly speaking this means we will miss wakeups if the address gets reused, and then someone does FUTEX_WAKE and expects to wake up a thread that started blocking on the old address before it got deallocated... but that seems really contrived?
@rust-lang/miri what do you think?