VYPR
High severityNVD Advisory· Published Dec 26, 2021· Updated Nov 18, 2024

CVE-2018-25023

CVE-2018-25023

Description

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.

AI Insight

LLM-synthesized narrative grounded in this CVE's description and references.

The smallvec crate before 0.6.13 for Rust uses mem::uninitialized() to create values of a user-supplied type, allowing uninitialized references and undefined behavior.

Vulnerability

The smallvec crate for Rust, versions prior to 0.6.13, uses mem::uninitialized() to create values of a user-supplied type T [4]. This is unsound when T is a reference type, which must be non-null and cannot remain uninitialized. The flaw was corrected by replacing mem::uninitialized() with MaybeUninit [1][2][4].

Exploitation

An attacker can trigger this vulnerability by providing a type T that is a reference (e.g., &u8) as the element type for a SmallVec. The crate's implementation then calls mem::uninitialized() to create an instance of that reference type, which results in an uninitialized reference. No special privileges or user interaction beyond controlling the generic type parameter is required.

Impact

This unsoundness can lead to undefined behavior (UB) because reading uninitialized memory as a reference violates Rust's safety guarantees. In practice, this could cause crashes, memory corruption, or potentially information disclosure, depending on how the uninitialized reference is used [4].

Mitigation

The flaw is patched in smallvec version 0.6.13 and later [4]. Users should upgrade to 0.6.13 or later. The RustSec advisory (RUSTSEC-2018-0018) also lists patched versions. No workarounds are known for unpatched versions [4].

AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
smallveccrates.io
< 0.6.130.6.13

Affected products

2

Patches

1
e64afc8c473d

Use MaybeUninit for storage of inline items.

https://github.com/servo/rust-smallvecThom ChiovoloniSep 8, 2019via ghsa
2 files changed · +54 40
  • Cargo.toml+2 1 modified
    @@ -1,6 +1,6 @@
     [package]
     name = "smallvec"
    -version = "0.6.12"
    +version = "0.6.13"
     authors = ["Simon Sapin <simon.sapin@exyr.org>"]
     license = "MIT/Apache-2.0"
     repository = "https://github.com/servo/rust-smallvec"
    @@ -23,6 +23,7 @@ path = "lib.rs"
     
     [dependencies]
     serde = { version = "1", optional = true }
    +maybe-uninit = "2.0"
     
     [dev_dependencies]
     bincode = "1.0.1"
    
  • lib.rs+52 39 modified
    @@ -45,18 +45,21 @@ use alloc::vec::Vec;
     #[cfg(feature = "serde")]
     extern crate serde;
     
    +extern crate maybe_uninit;
    +
     #[cfg(not(feature = "std"))]
     mod std {
         pub use core::*;
     }
     
    +use maybe_uninit::MaybeUninit;
    +
     use std::borrow::{Borrow, BorrowMut};
     use std::cmp;
     use std::fmt;
     use std::hash::{Hash, Hasher};
     use std::iter::{IntoIterator, FromIterator, repeat};
     use std::mem;
    -use std::mem::ManuallyDrop;
     use std::ops;
     use std::ptr;
     use std::slice;
    @@ -275,26 +278,28 @@ impl<'a, T: 'a> Drop for Drain<'a,T> {
     
     #[cfg(feature = "union")]
     union SmallVecData<A: Array> {
    -    inline: ManuallyDrop<A>,
    +    inline: MaybeUninit<A>,
         heap: (*mut A::Item, usize),
     }
     
     #[cfg(feature = "union")]
     impl<A: Array> SmallVecData<A> {
         #[inline]
    -    unsafe fn inline(&self) -> &A {
    -        &self.inline
    +    unsafe fn inline(&self) -> *const A::Item {
    +        self.inline.as_ptr() as *const A::Item
         }
         #[inline]
    -    unsafe fn inline_mut(&mut self) -> &mut A {
    -        &mut self.inline
    +    unsafe fn inline_mut(&mut self) -> *mut A::Item {
    +        self.inline.as_mut_ptr() as *mut A::Item
         }
         #[inline]
    -    fn from_inline(inline: A) -> SmallVecData<A> {
    -        SmallVecData { inline: ManuallyDrop::new(inline) }
    +    fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
    +        SmallVecData { inline }
         }
         #[inline]
    -    unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) }
    +    unsafe fn into_inline(self) -> MaybeUninit<A> {
    +        self.inline
    +    }
         #[inline]
         unsafe fn heap(&self) -> (*mut A::Item, usize) {
             self.heap
    @@ -311,34 +316,34 @@ impl<A: Array> SmallVecData<A> {
     
     #[cfg(not(feature = "union"))]
     enum SmallVecData<A: Array> {
    -    Inline(ManuallyDrop<A>),
    +    Inline(MaybeUninit<A>),
         Heap((*mut A::Item, usize)),
     }
     
     #[cfg(not(feature = "union"))]
     impl<A: Array> SmallVecData<A> {
         #[inline]
    -    unsafe fn inline(&self) -> &A {
    +    unsafe fn inline(&self) -> *const A::Item {
             match *self {
    -            SmallVecData::Inline(ref a) => a,
    +            SmallVecData::Inline(ref a) => a.as_ptr() as *const A::Item,
                 _ => debug_unreachable!(),
             }
         }
         #[inline]
    -    unsafe fn inline_mut(&mut self) -> &mut A {
    +    unsafe fn inline_mut(&mut self) -> *mut A::Item {
             match *self {
    -            SmallVecData::Inline(ref mut a) => a,
    +            SmallVecData::Inline(ref mut a) => a.as_mut_ptr() as *mut A::Item,
                 _ => debug_unreachable!(),
             }
         }
         #[inline]
    -    fn from_inline(inline: A) -> SmallVecData<A> {
    -        SmallVecData::Inline(ManuallyDrop::new(inline))
    +    fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
    +        SmallVecData::Inline(inline)
         }
         #[inline]
    -    unsafe fn into_inline(self) -> A {
    +    unsafe fn into_inline(self) -> MaybeUninit<A> {
             match self {
    -            SmallVecData::Inline(a) => ManuallyDrop::into_inner(a),
    +            SmallVecData::Inline(a) => a,
                 _ => debug_unreachable!(),
             }
         }
    @@ -403,11 +408,15 @@ impl<A: Array> SmallVec<A> {
         /// Construct an empty vector
         #[inline]
         pub fn new() -> SmallVec<A> {
    -        unsafe {
    -            SmallVec {
    -                capacity: 0,
    -                data: SmallVecData::from_inline(mem::uninitialized()),
    -            }
    +        // 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()),
             }
         }
     
    @@ -447,10 +456,10 @@ impl<A: Array> SmallVec<A> {
         pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> {
             if vec.capacity() <= A::size() {
                 unsafe {
    -                let mut data = SmallVecData::<A>::from_inline(mem::uninitialized());
    +                let mut data = SmallVecData::<A>::from_inline(MaybeUninit::uninit());
                     let len = vec.len();
                     vec.set_len(0);
    -                ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len);
    +                ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut(), len);
     
                     SmallVec {
                         capacity: len,
    @@ -483,7 +492,7 @@ impl<A: Array> SmallVec<A> {
         pub fn from_buf(buf: A) -> SmallVec<A> {
             SmallVec {
                 capacity: A::size(),
    -            data: SmallVecData::from_inline(buf),
    +            data: SmallVecData::from_inline(MaybeUninit::new(buf)),
             }
         }
     
    @@ -523,7 +532,7 @@ impl<A: Array> SmallVec<A> {
         pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec<A> {
             SmallVec {
                 capacity: len,
    -            data: SmallVecData::from_inline(buf),
    +            data: SmallVecData::from_inline(MaybeUninit::new(buf)),
             }
         }
     
    @@ -571,7 +580,7 @@ impl<A: Array> SmallVec<A> {
                     let (ptr, len) = self.data.heap();
                     (ptr, len, self.capacity)
                 } else {
    -                (self.data.inline().ptr(), self.capacity, A::size())
    +                (self.data.inline(), self.capacity, A::size())
                 }
             }
         }
    @@ -584,7 +593,7 @@ impl<A: Array> SmallVec<A> {
                     let &mut (ptr, ref mut len_ptr) = self.data.heap_mut();
                     (ptr, len_ptr, self.capacity)
                 } else {
    -                (self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size())
    +                (self.data.inline_mut(), &mut self.capacity, A::size())
                 }
             }
         }
    @@ -651,8 +660,8 @@ impl<A: Array> SmallVec<A> {
                     if unspilled {
                         return;
                     }
    -                self.data = SmallVecData::from_inline(mem::uninitialized());
    -                ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
    +                self.data = SmallVecData::from_inline(MaybeUninit::uninit());
    +                ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
                     self.capacity = len;
                 } else if new_cap != cap {
                     let mut vec = Vec::with_capacity(new_cap);
    @@ -717,8 +726,8 @@ impl<A: Array> SmallVec<A> {
             if self.inline_size() >= len {
                 unsafe {
                     let (ptr, len) = self.data.heap();
    -                self.data = SmallVecData::from_inline(mem::uninitialized());
    -                ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
    +                self.data = SmallVecData::from_inline(MaybeUninit::uninit());
    +                ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
                     deallocate(ptr, self.capacity);
                     self.capacity = len;
                 }
    @@ -883,7 +892,7 @@ impl<A: Array> SmallVec<A> {
                 unsafe {
                     let data = ptr::read(&self.data);
                     mem::forget(self);
    -                Ok(data.into_inline())
    +                Ok(data.into_inline().assume_init())
                 }
             }
         }
    @@ -1041,8 +1050,12 @@ impl<A: Array> SmallVec<A> where A::Item: Copy {
                 SmallVec {
                     capacity: len,
                     data: SmallVecData::from_inline(unsafe {
    -                    let mut data: A = mem::uninitialized();
    -                    ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len);
    +                    let mut data: MaybeUninit<A> = MaybeUninit::uninit();
    +                    ptr::copy_nonoverlapping(
    +                        slice.as_ptr(),
    +                        data.as_mut_ptr() as *mut A::Item,
    +                        len,
    +                    );
                         data
                     })
                 }
    @@ -1587,8 +1600,8 @@ macro_rules! impl_array(
                 unsafe impl<T> Array for [T; $size] {
                     type Item = T;
                     fn size() -> usize { $size }
    -                fn ptr(&self) -> *const T { self.as_ptr() }
    -                fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() }
    +                fn ptr(&self) -> *const T { unimplemented!() }
    +                fn ptr_mut(&mut self) -> *mut T { unimplemented!() }
                 }
             )+
         }
    @@ -1889,7 +1902,7 @@ mod tests {
             assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
         }
     
    -    #[cfg(feature = "std")]
    +    #[cfg(all(feature = "std", not(miri)))] // Miri currently does not support unwinding
         #[test]
         // https://github.com/servo/rust-smallvec/issues/96
         fn test_insert_many_panic() {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.