| #![warn(clippy::uninit_vec)] |
| |
| use std::cell::UnsafeCell; |
| use std::mem::MaybeUninit; |
| |
| #[derive(Default)] |
| struct MyVec { |
| vec: Vec<u8>, |
| } |
| |
| union MyOwnMaybeUninit { |
| value: u8, |
| uninit: (), |
| } |
| |
| // https://github.com/rust-lang/rust/issues/119620 |
| unsafe fn requires_paramenv<S>() { |
| unsafe { |
| let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(1); |
| //~^ uninit_vec |
| vec.set_len(1); |
| } |
| |
| let mut vec = Vec::<UnsafeCell<*mut S>>::with_capacity(2); |
| //~^ uninit_vec |
| unsafe { |
| vec.set_len(2); |
| } |
| } |
| |
| fn main() { |
| // with_capacity() -> set_len() should be detected |
| let mut vec: Vec<u8> = Vec::with_capacity(1000); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(200); |
| } |
| |
| // reserve() -> set_len() should be detected |
| vec.reserve(1000); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(200); |
| } |
| |
| // new() -> set_len() should be detected |
| let mut vec: Vec<u8> = Vec::new(); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(200); |
| } |
| |
| // default() -> set_len() should be detected |
| let mut vec: Vec<u8> = Default::default(); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(200); |
| } |
| |
| let mut vec: Vec<u8> = Vec::default(); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(200); |
| } |
| |
| // test when both calls are enclosed in the same unsafe block |
| unsafe { |
| let mut vec: Vec<u8> = Vec::with_capacity(1000); |
| //~^ uninit_vec |
| |
| vec.set_len(200); |
| |
| vec.reserve(1000); |
| //~^ uninit_vec |
| |
| vec.set_len(200); |
| } |
| |
| let mut vec: Vec<u8> = Vec::with_capacity(1000); |
| //~^ uninit_vec |
| |
| unsafe { |
| // test the case where there are other statements in the following unsafe block |
| vec.set_len(200); |
| assert_eq!(vec.len(), 200); |
| } |
| |
| // handle vec stored in the field of a struct |
| let mut my_vec = MyVec::default(); |
| my_vec.vec.reserve(1000); |
| //~^ uninit_vec |
| |
| unsafe { |
| my_vec.vec.set_len(200); |
| } |
| |
| my_vec.vec = Vec::with_capacity(1000); |
| //~^ uninit_vec |
| |
| unsafe { |
| my_vec.vec.set_len(200); |
| } |
| |
| // Test `#[allow(...)]` attributes on inner unsafe block (shouldn't trigger) |
| let mut vec: Vec<u8> = Vec::with_capacity(1000); |
| #[allow(clippy::uninit_vec)] |
| unsafe { |
| vec.set_len(200); |
| } |
| |
| // MaybeUninit-wrapped types should not be detected |
| unsafe { |
| let mut vec: Vec<MaybeUninit<u8>> = Vec::with_capacity(1000); |
| vec.set_len(200); |
| |
| let mut vec: Vec<(MaybeUninit<u8>, MaybeUninit<bool>)> = Vec::with_capacity(1000); |
| vec.set_len(200); |
| |
| let mut vec: Vec<(MaybeUninit<u8>, [MaybeUninit<bool>; 2])> = Vec::with_capacity(1000); |
| vec.set_len(200); |
| } |
| |
| // known false negative |
| let mut vec1: Vec<u8> = Vec::with_capacity(1000); |
| let mut vec2: Vec<u8> = Vec::with_capacity(1000); |
| unsafe { |
| vec1.set_len(200); |
| vec2.set_len(200); |
| } |
| |
| // set_len(0) should not be detected |
| let mut vec: Vec<u8> = Vec::with_capacity(1000); |
| unsafe { |
| vec.set_len(0); |
| } |
| |
| // ZSTs should not be detected |
| let mut vec: Vec<()> = Vec::with_capacity(1000); |
| unsafe { |
| vec.set_len(10); |
| } |
| |
| // unions should not be detected |
| let mut vec: Vec<MyOwnMaybeUninit> = Vec::with_capacity(1000); |
| unsafe { |
| vec.set_len(10); |
| } |
| |
| polymorphic::<()>(); |
| |
| fn polymorphic<T>() { |
| // We are conservative around polymorphic types. |
| let mut vec: Vec<T> = Vec::with_capacity(1000); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(10); |
| } |
| } |
| |
| fn poly_maybe_uninit<T>() { |
| // We are conservative around polymorphic types. |
| let mut vec: Vec<MaybeUninit<T>> = Vec::with_capacity(1000); |
| unsafe { |
| vec.set_len(10); |
| } |
| } |
| |
| fn nested_union<T>() { |
| let mut vec: Vec<UnsafeCell<MaybeUninit<T>>> = Vec::with_capacity(1); |
| unsafe { |
| vec.set_len(1); |
| } |
| } |
| |
| struct Recursive<T>(*const Recursive<T>, MaybeUninit<T>); |
| fn recursive_union<T>() { |
| // Make sure we don't stack overflow on recursive types. |
| // The pointer acts as the base case because it can't be uninit regardless of its pointee. |
| |
| let mut vec: Vec<Recursive<T>> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(1); |
| } |
| } |
| |
| #[repr(u8)] |
| enum Enum<T> { |
| Variant(T), |
| } |
| fn union_in_enum<T>() { |
| // Enums can have a discriminant that can't be uninit, so this should still warn |
| let mut vec: Vec<Enum<T>> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| |
| unsafe { |
| vec.set_len(1); |
| } |
| } |
| } |
| |
| mod issue_11715 { |
| use std::mem::MaybeUninit; |
| #[cfg(target_pointer_width = "64")] |
| const HUGE: usize = 4_294_967_296; |
| #[cfg(target_pointer_width = "32")] |
| const HUGE: usize = 268_435_455; |
| |
| fn large_maybeuninit_vec_ice() { |
| let mut v: Vec<[MaybeUninit<u64>; HUGE]> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| fn large_u8_vec_ice() { |
| let mut v: Vec<[u8; HUGE]> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| unsafe { v.set_len(1) }; |
| } |
| |
| fn large_nested_maybeuninit_vec_ice() { |
| let mut v: Vec<[[MaybeUninit<u64>; HUGE]; 2]> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| struct HeavyWrapperSafe([MaybeUninit<u64>; HUGE]); |
| fn large_struct_maybeuninit_vec_ice() { |
| let mut v: Vec<HeavyWrapperSafe> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| struct HeavyWrapperUnsafe([u8; HUGE]); |
| fn large_struct_u8_vec_ice() { |
| let mut v: Vec<HeavyWrapperUnsafe> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| unsafe { v.set_len(1) }; |
| } |
| |
| #[allow(clippy::large_enum_variant)] |
| enum HeavyEnum { |
| A([MaybeUninit<u64>; HUGE]), |
| B, |
| } |
| fn large_enum_vec_ice() { |
| let mut v: Vec<HeavyEnum> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| unsafe { v.set_len(1) }; |
| } |
| |
| enum Uninhabited {} |
| fn uninhabited_enum() { |
| let mut v: Vec<Uninhabited> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| enum SingleVariant { |
| OnlyOne, |
| } |
| fn single_variant_enum() { |
| let mut v: Vec<SingleVariant> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| enum OneVariantU8 { |
| ThisOne([u8; HUGE]), |
| } |
| fn one_variant_u8() { |
| let mut v: Vec<OneVariantU8> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| unsafe { v.set_len(1) }; |
| } |
| |
| enum OneVariantMaybeUninit { |
| ThisOne([MaybeUninit<u8>; HUGE]), |
| } |
| fn one_variant_maybe_uninit() { |
| let mut v: Vec<OneVariantMaybeUninit> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| fn generic_vec_lints<T>() { |
| let mut v: Vec<T> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| unsafe { v.set_len(1) }; |
| } |
| |
| fn generic_vec_maybeuninit<T>() { |
| let mut v: Vec<MaybeUninit<T>> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| trait Assoc { |
| type Item; |
| } |
| fn projection_vec_lints<T: Assoc>() { |
| let mut v: Vec<<T as Assoc>::Item> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| unsafe { v.set_len(1) }; |
| } |
| |
| struct Concrete; |
| impl Assoc for Concrete { |
| type Item = MaybeUninit<u8>; |
| } |
| fn normalized_projection_vec_ok() { |
| let mut v: Vec<<Concrete as Assoc>::Item> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| |
| enum E<T, U> { |
| Foo(MaybeUninit<T>), |
| Bar(U), |
| } |
| fn enum_uninhabited_zst() { |
| let mut v: Vec<E<u8, core::convert::Infallible>> = Vec::with_capacity(1); |
| unsafe { v.set_len(1) }; |
| } |
| fn enum_uninhabited_non_zst() { |
| let mut v: Vec<E<u8, (u8, core::convert::Infallible)>> = Vec::with_capacity(1); |
| //~^ uninit_vec |
| unsafe { v.set_len(1) }; |
| } |
| } |