Use MaybeUninit<T> for Uninitialized Memory

2026-08-30 浏览 (1)

id: mem-06 original_id: G.UNS.MEM.01 level: G impact: HIGH clippy: uninit_assumed_init, uninit_vec

Use MaybeUninit for Uninitialized Memory

Summary

Use MaybeUninit<T> instead of mem::uninitialized() or mem::zeroed() when working with uninitialized memory.

Rationale

  • mem::uninitialized() is deprecated and unsound
  • mem::zeroed() is UB for types where zero is invalid (references, NonZero, bool)
  • MaybeUninit<T> clearly marks memory as potentially uninitialized
  • Compiler can optimize based on initialization state

Bad Example

// DON'T: Use deprecated uninitialized
fn bad_uninit<T>() -> T {
    unsafe { std::mem::uninitialized() }  // Deprecated, UB
}

// DON'T: Use zeroed for types where zero is invalid
fn bad_zeroed() -> &'static str {
    unsafe { std::mem::zeroed() }  // UB: null reference
}

fn bad_zeroed_bool() -> bool {
    unsafe { std::mem::zeroed() }  // UB: 0 might not be valid bool
}

// DON'T: Transmute to "initialize"
fn bad_transmute() -> [String; 10] {
    unsafe { std::mem::transmute([0u8; std::mem::size_of::<[String; 10]>()]) }
}

// DON'T: Set Vec length without initializing
fn bad_vec() -> Vec<String> {
    let mut v = Vec::with_capacity(10);
    unsafe { v.set_len(10); }  // Elements are uninitialized!
    v
}

Good Example

use std::mem::MaybeUninit;

// DO: Use MaybeUninit for delayed initialization
fn good_array() -> [String; 10] {
    let mut arr: [MaybeUninit<String>; 10] =
        unsafe { MaybeUninit::uninit().assume_init() };

    for (i, elem) in arr.iter_mut().enumerate() {
        elem.write(format!("item {}", i));
    }

    // SAFETY: All elements initialized above
    unsafe { std::mem::transmute::<_, [String; 10]>(arr) }
}

// DO: Use MaybeUninit with arrays (cleaner with array_assume_init)
fn good_array_nightly() -> [String; 10] {
    let mut arr: [MaybeUninit<String>; 10] =
        [const { MaybeUninit::uninit() }; 10];

    for (i, elem) in arr.iter_mut().enumerate() {
        elem.write(format!("item {}", i));
    }

    // On nightly: arr.map(|e| unsafe { e.assume_init() })
    unsafe { MaybeUninit::array_assume_init(arr) }
}

// DO: Use zeroed only for types where it's valid
fn good_zeroed() -> [u8; 1024] {
    // SAFETY: All-zero bytes is valid for u8
    unsafe { std::mem::zeroed() }
}

// DO: Initialize buffer properly
fn good_vec() -> Vec<u8> {
    let mut v = Vec::with_capacity(1024);

    // Option 1: Resize with default value
    v.resize(1024, 0);

    // Option 2: Use spare_capacity_mut
    let spare = v.spare_capacity_mut();
    for elem in spare.iter_mut().take(1024) {
        elem.write(0);
    }
    unsafe { v.set_len(1024); }

    v
}

// DO: Use MaybeUninit::uninit_array (nightly) or const array
fn good_uninit_array<const N: usize>() -> [MaybeUninit<u8>; N] {
    // Stable: create array of uninit
    [const { MaybeUninit::uninit() }; N]
}

MaybeUninit API

use std::mem::MaybeUninit;

// Creation
let uninit: MaybeUninit<T> = MaybeUninit::uninit();
let zeroed: MaybeUninit<T> = MaybeUninit::zeroed();
let init: MaybeUninit<T> = MaybeUninit::new(value);

// Writing
uninit.write(value);  // Returns &mut T

// Reading (unsafe)
let value: T = unsafe { uninit.assume_init() };
let ref_: &T = unsafe { uninit.assume_init_ref() };
let mut_: &mut T = unsafe { uninit.assume_init_mut() };

// Pointer access
let ptr: *const T = uninit.as_ptr();
let mut_ptr: *mut T = uninit.as_mut_ptr();

Checklist

  • Am I using mem::uninitialized()? → Replace with MaybeUninit
  • Am I using mem::zeroed() for non-POD types? → Use MaybeUninit
  • Am I setting Vec length without initialization? → Use proper initialization
  • Have I initialized all MaybeUninit before assume_init?

Related Rules

  • safety-03: Don't expose uninitialized memory in APIs
  • safety-01: Panic safety with partial initialization

你可能感兴趣的文章

Do Not Expose Raw Pointers in Public APIs

Unsafe Code Authors Must Verify Safety Invariants

Ensure Consistent Data Layout for Custom Types

Add Safety Section in Docs for Public Unsafe Functions

Do Not Use Union Variants Across Different Lifetimes

Ensure C-ABI Compatibility for Strings Between Rust and C

Do Not Dereference Pointers Cast to Misaligned Types

Use Dedicated Opaque Type Pointers Instead of c_void for C Opaque Types

Choose Appropriate Data Layout for Struct/Tuple/Enum

Handle Errors Properly in FFI

  • 所属分类: AI
  • 本文标签: rust
  • 版权声明: 本文链接 https://seaxiang.com/blog/PVBwLRGI