Are these functions effectively equivalent?

unsafe fn memset(s: *mut u8, c: u8, n: usize) {
    // function 0: std::ptr::write_bytes(s, c, n)
    // function 1: core::intrinsics::volatile_set_memory(s, c, n);
}

I know function 1 works as intended. However, it is not a stable library. Will function 0 be a valid drop-in replacement?

No, they are not equivalent. The volatile_set_memory method performs a volatile write, which write_bytes does not.

1 Like

What's the difference between a volatile write and a normal write?

What would be a way to replace function 1 in stable rust?

The goal is just to replace a series of bytes starting at position s of length n with value c

A volatile read or write operation is intended for the case where your memory behaves like an IO device. For example, some chips might have specific locations in memory where writing to them has some effect such as turning on an LED, and the write therefore should not get optimized out even if the written value is never read.

Volatile operations are not intended for thread safety. That's the job of atomics. (note that volatile is intended for thread safety in some other languages such as Java)

5 Likes

Interesting ... so whether or not write_bytes or volatile_set_memory is needed depends on context. If I never want the optimization to occur, then volatile is needed. Would using a simple for loop, setting each pointee value to c ensure that the compiler won't optimize it out? Or, is volatile necessary?

In what case are you asking whether you need volatile?

Specifically, I need to zeroize memory on drop via memset(ptr, 0, len). I know I could just use the zeroize crate, but I'd prefer to be as lean as possible.

The zeroize crate does this:

#[inline]
unsafe fn volatile_set<T: Copy + Sized>(dst: *mut T, src: T, count: usize) {
    // TODO(tarcieri): use `volatile_set_memory` when stabilized
    for i in 0..count {
        // Safety:
        //
        // This is safe because there is room for at least `count` objects of type `T` in the
        // allocation pointed to by `dst`, because `count <= isize::MAX` and because
        // `dst.add(count)` must not wrap around the address space.
        let ptr = dst.add(i);
        // Safety:
        //
        // This is safe, because the pointer is valid and because `dst` is well aligned for `T` and
        // `ptr` is an offset of `dst` by a multiple of `mem::size_of::<T>()` bytes.
        ptr::write_volatile(ptr, src);
    }
}
4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.