Skip to content

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

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

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 ^^

Sign up for free to join this conversation on GitHub. Already have an account? Sign in 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