I'm adding the nmount call to libc and ran into some behavior I don't understand and was hoping someone could shed some light. I have a function that builds an libc::iovec struct which I then pass to the nmount call, which on FreeBSD is the replacement for the mount sys call.
I must be clobbering memory somewhere but I really don't understand how. I was hoping someone might have some idea of why this is happening. I think each instance of the iov_base member of iovec should point to a different piece of memory. I thought the issue might be a naive understanding of the borrow checking, so I moved the code outside the unsafe block where I actually call the nmount sys call.
fn iovec_from_string(name: &str) -> libc::iovec {
println!("processing {}", name);
let cstring = CString::new(name).expect("Failed to covert string to to C String");
let bytes = cstring.as_bytes_with_nul();
libc::iovec {
iov_base: bytes.as_ptr() as *mut libc::c_void,
iov_len: name.len() + 1,
}
}
I then create an array of libc::iovec objects:
let fstype_option_name = "fstype";
let fstype_option_value = "ufs";
let fspath_option_name = "fspath";
let fspath_option_value = "/mnt";
let from_option_name = "from";
let from_option_value = "/dev/da7p2";
let mount_options_ptr: [libc::iovec; 6] = [
iovec_from_string(&fstype_option_name),
iovec_from_string(&fstype_option_value),
iovec_from_string(&fspath_option_name),
iovec_from_string(&fspath_option_value),
iovec_from_string(&from_option_name),
iovec_from_string(&from_option_value),
];
fn print_iovec(iov: &libc::iovec) {
println!("{} bytes", iov.iov_len);
println!("{:X} addr", iov.iov_base as u64);
}
When I run this, the output indicates it's using the same block of member for each instance of the libc::iovec, even though I had passed a different string into each call of the iovec_from_string function. Except for the last iovec instance, which points to a different piece of memory.
processing fstype
processing ufs
processing fspath
processing /mnt
processing from
processing /dev/da7p2
7 bytes
8014F8030 addr
4 bytes
8014F8030 addr
7 bytes
8014F8030 addr
5 bytes
8014F8030 addr
5 bytes
8014F8030 addr
11 bytes
80153E000 addr
I wrote a dummy library to stand in for nmount and dump the values the library saw when called from Rust. Sure enough, it's seeing the same memory contents and leading nulls have been inserted.
Calling mount
6 iovec structs
7
00 72 6f 6d 00 68 00
. r o m . h .
4
00 72 6f 6d
. r o m
7
00 72 6f 6d 00 68 00
. r o m . h .
5
00 72 6f 6d 00
. r o m .
5
00 72 6f 6d 00
. r o m .
11
00 64 65 76 2f 64 61 37 70 32 00
. d e v / d a 7 p 2 .
Flag: 0