Skip to content
This repository has been archived by the owner on Feb 7, 2021. It is now read-only.

Commit

Permalink
Merge pull request #6 from TyPR124/uninit_bytes_ub
Browse files Browse the repository at this point in the history
Fix UB when T contains uninit bytes
  • Loading branch information
Lucretiel authored Feb 11, 2020
2 parents fb1d8d1 + 8c5da8c commit 9ed4c66
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 11 deletions.
62 changes: 52 additions & 10 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ extern crate alloc;

use alloc::boxed::Box;
use core::fmt;
use core::mem::{self, size_of, MaybeUninit};
use core::mem::{self, MaybeUninit};
use core::ops::{Deref, DerefMut};
use core::ptr;

Expand Down Expand Up @@ -217,15 +217,11 @@ impl<T> Stowaway<T> {
}
SizeClass::Boxed => Box::into_raw(Box::new(value)),
SizeClass::Packed => {
// If T smaller than *mut T, we need to initialize the extra
// bytes. TODO: figure out a way to initialize these bytes (to
// the satisfaction of defined behavior) without zeroing them,
// if possible.
let mut blob: MaybeUninit<*mut T> = if size_of::<T>() < size_of::<*mut T>() {
MaybeUninit::zeroed()
} else {
MaybeUninit::uninit()
};
// Need to init (zero) all bytes. Even if sizeof(T) == sizeof(*T),
// T may contain unused/uninit padding bytes. TODO: figure out a way
// to initialize these bytes (to the satisfaction of defined
// behavior) without zeroing them, if possible.
let mut blob: MaybeUninit<*mut T> = MaybeUninit::zeroed();

let ptr = blob.as_mut_ptr();

Expand Down Expand Up @@ -320,6 +316,52 @@ impl<T> Stowaway<T> {
storage as *mut ()
}
}
// These tests are designed to detect undefined behavior in miri under naive,
// incorrect implementations of Stowaway.
#[cfg(test)]
mod test_for_uninit_bytes {
use crate::{stow, unstow};
#[test]
fn zst() {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Zst;
let x = Zst;
let stowed = stow(x);
let unstowed = unsafe { unstow(stowed) };
assert_eq!(x, unstowed);
}
#[test]
fn small_t() {
let x: u8 = 7;
let stowed = stow(x);
let unstowed = unsafe { unstow(stowed) };
assert_eq!(x, unstowed);
}
#[test]
fn t_with_gaps_32() {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Gaps32 {
a: u8,
b: u16,
}
let x = Gaps32 { a: 7, b: 42 };
let stowed = stow(x);
let unstowed = unsafe { unstow(stowed) };
assert_eq!(x, unstowed);
}
#[test]
fn t_with_gaps_64() {
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
struct Gaps64 {
a: u8,
b: u32,
}
let x = Gaps64 { a: 7, b: 42 };
let stowed = stow(x);
let unstowed = unsafe { unstow(stowed) };
assert_eq!(x, unstowed);
}
}

impl<T> Drop for Stowaway<T> {
fn drop(&mut self) {
Expand Down
2 changes: 1 addition & 1 deletion test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ cargo clean
cargo fmt -- --check
cargo clippy -- -Dwarnings
cargo test
cargo miri test
cargo +nightly miri test

0 comments on commit 9ed4c66

Please sign in to comment.