mio issueshttps://gitlab.redox-os.org/redox-os/mio/-/issues2023-07-02T15:01:14Zhttps://gitlab.redox-os.org/redox-os/mio/-/issues/1Possible data race using Overlapped2023-07-02T15:01:14ZBoqin QinPossible data race using Overlappedhttps://gitlab.redox-os.org/redox-os/mio/blob/master/src/sys/windows/selector.rs#L493
Struct Overlapped implements Sync trait so as to be shared across threads by reference.
It contains a UnsafeCell, and its method `as_mut_ptr` will ret...https://gitlab.redox-os.org/redox-os/mio/blob/master/src/sys/windows/selector.rs#L493
Struct Overlapped implements Sync trait so as to be shared across threads by reference.
It contains a UnsafeCell, and its method `as_mut_ptr` will return a mutable ptr to the inner data.
This may cause a crash if one thread writes the data while another is accessing it, all by immutable reference of the struct and will bypass compiler checking.
It is rather unsafe but we marked it as safe!!!
I searched for a ref-counting version of this struct, which is much safer.
https://github.com/tokio-rs/mio/blob/master/src/sys/windows/selector.rs#L81
My suggestion is to replace the current Overlapped with this version.https://gitlab.redox-os.org/redox-os/mio/-/issues/2Atomicity Violation in dlsym DlSym::get(&self)2023-09-24T09:21:25ZBoqin QinAtomicity Violation in dlsym DlSym::get(&self)https://gitlab.redox-os.org/redox-os/mio/blob/master/src/sys/unix/dlsym.rs#L19-46
```
pub fn get(&self) -> Option<&F> {
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
unsafe {
if self.addr.load(...https://gitlab.redox-os.org/redox-os/mio/blob/master/src/sys/unix/dlsym.rs#L19-46
```
pub fn get(&self) -> Option<&F> {
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
unsafe {
if self.addr.load(Ordering::SeqCst) == 0 { // 1
self.addr.store(fetch(self.name), Ordering::SeqCst); // 2, 3
}
if self.addr.load(Ordering::SeqCst) == 1 { // 4
None
} else {
mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
}
}
}
```
This bug is an atomicity violation. addr is an AtomicUsize, which can be converted to a function reference in function get().
In the buggy code,
1. function get() first check if addr is 0.
2. If not then call fetch()
3. and store the returned value (1 or other) to addr.
4. Then it checks if addr is 1. If not, convert the addr into a function reference.
Because the struct is Sync (all its fields are Sync) and the function takes immutable self (&self) as parameter,
the function can be called by two threads simultaneously and the following execution may occur:
| T1 | T2 |
| ------ | ------ |
| check addr.load() == 0 | |
| tmp1 = fetch(name) | |
| | check addr.load() == 0 |
| | tmp2 = fetch(name) (suppose tmp2 == 1)|
| | addr.store(tmp2)|
| addr.store(tmp1) (suppose tmp1 != 1)||
|| check addr.load() != 1|
|| convert addr (currently tmp1) to a function reference and returned|
But originally it should return None because tmp2 == 1