FFIの境界を越えてポインターサイズのintに収まるトランザクション型を支援するライブラリを開発しています。次のような構造体があるとします。
use std::mem::{size_of, align_of};
struct PaddingDemo {
data: u8,
force_pad: [usize; 0]
}
assert_eq!(size_of::<PaddingDemo>(), size_of::<usize>());
assert_eq!(align_of::<PaddingDemo>(), align_of::<usize>());
この構造体には、1データバイトと7パディングバイトがあります。この構造体のインスタンスをaにパックしusize
、FFI境界の反対側でアンパックします。このライブラリーは汎用なので、私はMaybeUninit
and を使用していptr::write
ます:
use std::ptr;
use std::mem::MaybeUninit;
let data = PaddingDemo { data: 12, force_pad: [] };
// In order to ensure all the bytes are initialized,
// zero-initialize the buffer
let mut packed: MaybeUninit<usize> = MaybeUninit::zeroed();
let ptr = packed.as_mut_ptr() as *mut PaddingDemo;
let packed_int = unsafe {
std::ptr::write(ptr, data);
packed.assume_init()
};
// Attempt to trigger UB in Miri by reading the
// possibly uninitialized bytes
let copied = unsafe { ptr::read(&packed_int) };
そのassume_init
呼び出しは未定義の動作を引き起こしましたか?つまり、ptr::write
が構造体をバッファにコピーするとき、パディングバイトの初期化されていない状態をコピーして、初期化された状態をゼロバイトとして上書きしますか?
現在、このコードまたは類似のコードをMiriで実行すると、未定義の動作は検出されません。ただし、githubでのこの問題に関する説明に従って、ptr::write
これらのパディングバイトをコピーすること、さらにはそれらの初期化されていないことをコピーすることが許可されていると考えられます。本当?のドキュメントでptr::write
は、これについてはまったく触れられておらず、初期化されていないメモリに関するノミコンのセクションについても触れていません。