src/unsafe-deep-dive/rules-of-the-game/copying-memory/exposed-unsafe.md
# // Copyright 2026 Google LLC
# // SPDX-License-Identifier: Apache-2.0
#
pub fn copy(dest: &mut [u8], source: *const u8) {
let source = {
let mut len = 0;
let mut end = source;
while unsafe { *end != 0 } {
len += 1;
end = unsafe { end.add(1) };
}
unsafe { std::slice::from_raw_parts(source, len + 1) }
};
for (dest, src) in dest.iter_mut().zip(source) {
*dest = *src;
}
}
fn main() {
let a = [114, 117, 115, 116].as_ptr();
let b = &mut [82, 85, 83, 84, 0];
println!("{}", String::from_utf8_lossy(b));
copy(b, a);
println!("{}", String::from_utf8_lossy(b));
}
The functionality of copying bytes from one place to the next remains the same.
“However, we need to manually create a slice. To do that, we first need to find the end of the data.
“As we’re working with text, we’ll use the C convention of a null-terminated string.
Compile the code. See that the output remains the same.
“An unsound function can still work correctly for some inputs. Just because your tests pass, does not mean that you have a sound function.”
“Can anyone spot any issues?”
source pointer might be nullsource pointer might be dangling, i.e. point to freed or uninitialized
memorysource might not be null-terminated“Assume that we cannot change the function signature, what improvements could we make to the code to address these issues?”
if source.is_null() { return; })“Some safety requirements are impossible to defensively check for, however, i.e.:”
“How can we make this function sound?”
source input argument to something that has a known
length, i.e. use a slice like the previous example.