Skip to content

  • Projects
  • Groups
  • Snippets
  • Help
    • Loading...
    • Help
    • Support
    • Submit feedback
    • Contribute to GitLab
  • Sign in / Register
M
mio
  • Project
    • Project
    • Details
    • Activity
    • Releases
    • Cycle Analytics
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Charts
  • Issues 2
    • Issues 2
    • List
    • Boards
    • Labels
    • Milestones
  • Merge Requests 0
    • Merge Requests 0
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
    • Charts
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Charts
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • redox-os
  • mio
  • Issues
  • #2

Closed
Open
Opened Nov 21, 2019 by Boqin Qin@BurtonQin
  • Report abuse
  • New issue
Report abuse New issue

Atomicity 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(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

Edited Nov 21, 2019 by Boqin Qin
Assignee
Assign to
None
Milestone
None
Assign milestone
Time tracking
None
Due date
None
0
Labels
None
Assign labels
  • View project labels
Reference: redox-os/mio#2