Skip to content
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

Warn if 'nonstandard Clone' used in vec! #4288

Open
ralfbiedert opened this issue Jul 20, 2019 · 4 comments
Open

Warn if 'nonstandard Clone' used in vec! #4288

ralfbiedert opened this issue Jul 20, 2019 · 4 comments
Labels
A-lint Area: New lints L-correctness Lint: Belongs in the correctness lint group

Comments

@ralfbiedert
Copy link

Background

Here is the essence of a bug that took me several hours to find in a larger code base. The code originally came from a much larger, multi-threaded function that fed data into a machine learning system. Instead of asserting, it just produced inputs that subtly changed other outputs.

use std::sync::{Arc, Mutex};

#[derive(Default, Clone)]
struct Entry<T> {
    id: usize,
    data: Arc<Mutex<T>>,
}

pub fn main() {
    let mut entries = vec![Entry::default(); 10];

    for (i, e) in entries.iter_mut().enumerate() {
        e.id = i;
        *e.data.lock().unwrap() = i;
    }

    let entry_0 = &entries[0];

    assert_eq!(entry_0.id, *entry_0.data.lock().unwrap());
}

In our project we had the following lints and warning enabled:

#![forbid(unsafe_code)]
#![warn(clippy::all)]
#![warn(clippy::nursery)]
#![warn(clippy::pedantic)]
#![allow(clippy::inline_always)] // Globally allow "inline" because we do it too much.
#![allow(clippy::module_name_repetitions)] // We have too many of these

Analysis

The bug comes from combining a struct S {} that contains an Arc with the vec![T; N] macro. The official documentation even warns against this sort of behavior:

This will use clone to duplicate an expression, so one should be careful using this with types having a nonstandard Clone implementation. For example, vec![Rc::new(1); 5] will create a vector of five references to the same boxed integer value, not five references pointing to independently boxed integers.

However, my intuition is that most people are so used to vec![S; 10] meaning "give me 10 independent instances of S" that this 'nonstandard case' will be somewhat surprising.

Suggestion

This bug could have been avoided if Clippy warned against known 'nonstandard' Clone implementations used in vec!. For starters, that could be any call to vec![T; N], where T contains an Arc or Rc.

@flip1995 flip1995 added L-correctness Lint: Belongs in the correctness lint group A-lint Area: New lints labels Jul 22, 2019
@basil-cow
Copy link
Contributor

I think we wouldn't want to fire the lint if some type on the path to the Arc has a custom Clone implementation, or should we lint that anyway?

@ralfbiedert
Copy link
Author

I'm not sure.

If the lint isn't 100% accurate I'd probably rather have a false positive I can silence, than having subtle errors caused by the combination of two innocent constructs possibly far apart.

On the other hand, I wouldn't want too many false positives, and I don't know how prevalent those constructs are.

@basil-cow
Copy link
Contributor

Ok, I'll write a draft sometime soon and feed it some codebases to see how common it is

@camsteffen
Copy link
Contributor

Same as #3377, except the Arc is buried in a struct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-lint Area: New lints L-correctness Lint: Belongs in the correctness lint group
Projects
None yet
Development

No branches or pull requests

4 participants