Skip to content

arc::Weak::upgrade does not account for overflow #30031

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Closed
Tracked by #10
apasel422 opened this issue Nov 24, 2015 · 5 comments
Closed
Tracked by #10

arc::Weak::upgrade does not account for overflow #30031

apasel422 opened this issue Nov 24, 2015 · 5 comments
Labels
A-atomic Area: Atomics, barriers, and sync primitives E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness

Comments

@apasel422
Copy link
Contributor

Similar to the issue fixed in #27174, these two methods do not account for overflow, causing use-after-frees in extremely contrived situations on machines with 32-bit usizes.

Both of these examples exhibit the erroneous behavior when compiled and run with -C opt-level=3 --target=i686-unknown-linux-gnu:

downgrade.rs:

use std::sync::Arc;

fn main() {
    let a = Arc::new("42".to_owned());

    for _ in 0..std::usize::MAX - 2 {
        let w = Arc::downgrade(&a); // add 1 to the weak count
        std::mem::forget(w);        // avoid decrementing the weak count
    }

    // the weak count is now `std::usize::MAX - 1`

    {
        let w = Arc::downgrade(&a); // add 1 to the weak count
        let x = w.clone();          // add 1 to the weak count so it wraps to 0
        drop(w);                    // drop `w`, deallocating the underlying `String`
        drop(x);                    // drop `x`, trying to deallocate the same `String`
    }
}

upgrade.rs:

use std::sync::Arc;

fn main() {
    let a = Arc::new("42".to_owned());
    let w = Arc::downgrade(&a);

    for _ in 0..std::usize::MAX - 1 {
        let b = w.upgrade(); // add 1 to the strong count
        std::mem::forget(b); // avoid decrementing the strong count
    }

    // the strong count is now `std::usize::MAX`

    {
        let b = w.upgrade().unwrap(); // add 1 to the strong count so it wraps to 0
        let c = b.clone();            // add 1 to the strong count so it is 1
        drop(c);                      // drop `c`, dropping the underlying `String`
    }

    println!("{:?}", a); // accesses the dropped `String`
}

Note that I've been working on a general consolidation of both reference-counted types at https://github.com/apasel422/ref_count.

@apasel422 apasel422 added A-libs I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. labels Nov 24, 2015
@steveklabnik steveklabnik added the I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness label Nov 24, 2015
@Gankra Gankra added the E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. label Nov 24, 2015
@Gankra
Copy link
Contributor

Gankra commented Nov 24, 2015

The fix to this is exactly the same as the rest. Add a check, abort the program.

@apasel422
Copy link
Contributor Author

@gankro Yup, working on it now.

@apasel422
Copy link
Contributor Author

Actually, because Arc::downgrade explicitly checks for usize::MAX, I'm not sure it needs to compare with MAX_REFCOUNT. The crash I was getting in the downgrade.rs example above was actually from calling abort in clone.

Does that seem right to you, @gankro?

@Gankra
Copy link
Contributor

Gankra commented Nov 24, 2015

Probably? I'm pretty high on cough-syrup and stress right now.

I wouldn't expect any sound advice for the next two weeks.

@apasel422 apasel422 changed the title Arc::downgrade and Weak::upgrade do not account for overflow arc::Weak::upgrade does not account for overflow Nov 24, 2015
Manishearth added a commit to Manishearth/rust that referenced this issue Nov 25, 2015
@workingjubilee workingjubilee added the A-atomic Area: Atomics, barriers, and sync primitives label Mar 3, 2023
@m-ou-se
Copy link
Member

m-ou-se commented Mar 3, 2023

[..] not sure it needs to compare with MAX_REFCOUNT [..]

Turns out Arc::downgrade does need to compare with MAX_REFCOUNT: #108706 ^^

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
A-atomic Area: Atomics, barriers, and sync primitives E-easy Call for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue. I-crash Issue: The compiler crashes (SIGSEGV, SIGABRT, etc). Use I-ICE instead when the compiler panics. I-unsound Issue: A soundness hole (worst kind of bug), see: https://en.wikipedia.org/wiki/Soundness
Projects
None yet
Development

No branches or pull requests

5 participants