CVE-2018-25023 (Rust, published 2021-12-27T00:15Z)
Description: value: An issue was discovered in the smallvec crate before 0.6.13 for Rust. It can create an uninitialized value of any type, including a reference type.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-908 \u2014 Use of Uninitialized Resource
The product uses or accesses a resource that has not been initialized.
Repository: https://github.com/servo/rust-smallvec
Files changed:
Cargo.toml
lib.rs
Commit message: Use MaybeUninit for storage of inline items.

This is a backport of #162 to the smallvec 0.6 branch. To avoid bumping the
minimum Rust version, the `maybe-uninit` crate is used in place of
`std::mem::MaybeUninit`.  To avoid breaking changes, the `Array::ptr` and
`ptr_mut` methods are retained but are no longer used, and the API to
`from_buf_and_len_unchecked` is unchanged.


Vulnerable code:
version = "0.6.12"
use std::mem::ManuallyDrop;
    inline: ManuallyDrop<A>,
    unsafe fn inline(&self) -> &A {
        &self.inline
    unsafe fn inline_mut(&mut self) -> &mut A {
        &mut self.inline
    fn from_inline(inline: A) -> SmallVecData<A> {
        SmallVecData { inline: ManuallyDrop::new(inline) }
    unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) }
    Inline(ManuallyDrop<A>),
    unsafe fn inline(&self) -> &A {
            SmallVecData::Inline(ref a) => a,
    unsafe fn inline_mut(&mut self) -> &mut A {
            SmallVecData::Inline(ref mut a) => a,
    fn from_inline(inline: A) -> SmallVecData<A> {
        SmallVecData::Inline(ManuallyDrop::new(inline))
    unsafe fn into_inline(self) -> A {
            SmallVecData::Inline(a) => ManuallyDrop::into_inner(a),
        unsafe {
            SmallVec {
                capacity: 0,
                data: SmallVecData::from_inline(mem::uninitialized()),
            }
                let mut data = SmallVecData::<A>::from_inline(mem::uninitialized());
                ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len);
            data: SmallVecData::from_inline(buf),
            data: SmallVecData::from_inline(buf),
                (self.data.inline().ptr(), self.capacity, A::size())
                (self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size())
                self.data = SmallVecData::from_inline(mem::uninitialized());
                ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
                self.data = SmallVecData::from_inline(mem::uninitialized());
                ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
                Ok(data.into_inline())
                    let mut data: A = mem::uninitialized();
                    ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len);
                fn ptr(&self) -> *const T { self.as_ptr() }
                fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() }
    #[cfg(feature = "std")]

Fixed code:
version = "0.6.13"
maybe-uninit = "2.0"
extern crate maybe_uninit;

use maybe_uninit::MaybeUninit;

    inline: MaybeUninit<A>,
    unsafe fn inline(&self) -> *const A::Item {
        self.inline.as_ptr() as *const A::Item
    unsafe fn inline_mut(&mut self) -> *mut A::Item {
        self.inline.as_mut_ptr() as *mut A::Item
    fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
        SmallVecData { inline }
    unsafe fn into_inline(self) -> MaybeUninit<A> {
        self.inline
    }
    Inline(MaybeUninit<A>),
    unsafe fn inline(&self) -> *const A::Item {
            SmallVecData::Inline(ref a) => a.as_ptr() as *const A::Item,
    unsafe fn inline_mut(&mut self) -> *mut A::Item {
            SmallVecData::Inline(ref mut a) => a.as_mut_ptr() as *mut A::Item,
    fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
        SmallVecData::Inline(inline)
    unsafe fn into_inline(self) -> MaybeUninit<A> {
            SmallVecData::Inline(a) => a,
        // Try to detect invalid custom implementations of `Array`. Hopefuly,
        // this check should be optimized away entirely for valid ones.
        assert!(
            mem::size_of::<A>() == A::size() * mem::size_of::<A::Item>()
                && mem::align_of::<A>() >= mem::align_of::<A::Item>()
        );
        SmallVec {
            capacity: 0,
            data: SmallVecData::from_inline(MaybeUninit::uninit()),
                let mut data = SmallVecData::<A>::from_inline(MaybeUninit::uninit());
                ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut(), len);
            data: SmallVecData::from_inline(MaybeUninit::new(buf)),
            data: SmallVecData::from_inline(MaybeUninit::new(buf)),
                (self.data.inline(), self.capacity, A::size())
                (self.data.inline_mut(), &mut self.capacity, A::size())
                self.data = SmallVecData::from_inline(MaybeUninit::uninit());
                ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
                self.data = SmallVecData::from_inline(MaybeUninit::uninit());
                ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
                Ok(data.into_inline().assume_init())
                    let mut data: MaybeUninit<A> = MaybeUninit::uninit();
                    ptr::copy_nonoverlapping(
                        slice.as_ptr(),
                        data.as_mut_ptr() as *mut A::Item,
                        len,
                    );
                fn ptr(&self) -> *const T { unimplemented!() }
                fn ptr_mut(&mut self) -> *mut T { unimplemented!() }
    #[cfg(all(feature = "std", not(miri)))] // Miri currently does not support unwinding