rust-lang / rust-lang/rust-clippy
unsound trait impl on union
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 13.5k
- Forks
- 2.2k
- Avg merge
- 2d 10h
- Merged PRs (30d)
- 32
Description
What it does
Warns if a trait is manually implemented on a union type, if it's not safe to do so.
For example
#[repr(C)]
pub union Foo {
bar: u32,
baz: u64
}
impl PartialEq on Foo {
fn partial_eq(&self, &other: Self) -> bool {
// Unsound! The baz field may be uninitialized data, if either argument was initialized like
// let x = Foo{bar: 42}
self.baz == other.baz
}
}
A common pattern for using unions is to initialize only the fields one intends to use. But there's no way for most trait impls to know which fields those are. Accessing an uninitialized field is undefined behavior. Even if the entire object was zero-initialized like let mut x: Foo = mem::zeroed(); x.bar =42, it's still not possible to correctly implement PartialEq, because the implementation doesn't know which fields "matter". For example:
let mut x = Foo{baz: 0x1111111111111111};
let mut y = Foo{baz: 0x2222222222222222};
x.bar = 42;
y.bar = 42;
assert_eq!(x, y);
In this example, logically x should equal y. But any PartialEq implementation would disagree, if it checks all of the struct's bits.
Similar arguments could be made for Hash, PartialOrd, and even Debug.
Lint Name
unsound_trait_impl_on_union
Category
correctness
Advantage
It will prevent undefined behavior, and prevent incorrect behavior of basic operations like ==. Such a lint could've caught bugs like https://github.com/rust-lang/libc/issues/2816 .
Drawbacks
Occasionally it may actually be ok to implement these traits on a union, for example when every member has the same size.
Example
#[repr(C)]
pub union Foo {
bar: u32,
baz: u64
}
impl PartialEq on Foo {
fn partial_eq(&self, &other: Self) -> bool {
// Unsound! The baz field may be uninitialized data, if either argument was initialized like
// let x = Foo{bar: 42}
self.baz == other.baz
}
}
The PartialEq implementation should be omitted. There's simply no way to do it correctly.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Use the issue's unsound_trait_impl_on_union proposal and its PartialEq, Hash, PartialOrd, and Debug examples as the behavioral scope. Determine how the lint should identify unsafe or incorrect trait implementations on unions, including the stated same-size-member exception; done means the lint prevents the described cases without rejecting valid implementations.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100