Reputation: 3765
I have the following rust code:
pub struct Settings {
pub vec: Vec<usize>,
pub index: usize,
}
pub fn add_to_settings_vec(ptr: *mut Settings) {
// create a box from the pointer
let boxed_settings = unsafe { Box::from_raw(ptr) };
// get the value in the box
let mut settings = *boxed_settings;
// mutate the value
settings.vec.push(123);
// create a new box and get a raw pointer to it so the value isn't deallocated
Box::into_raw(Box::new(project));
}
I want to make sure that the pointer that was passed as a function parameter stays valid and points to the modified Settings
value, even after adding an element to the vector of the unboxed Settings
value.
I think I'll need the following steps to achieve my goal:
Settings
Settings
don't get deallocatedSettings
This should probably be possible as the Settings
value is of a fixed size, as far as I have understood it, even with the vector, as the vector grows its the memory at a different location.
I have looked at the docs over at https://doc.rust-lang.org/std/boxed/struct.Box.html but I haven't been able to figure this out.
I have also read about pins, but I do not know how or when to use them: https://doc.rust-lang.org/std/pin/index.html.
Does the above code always leave the passed in pointer in tact? I'd appreciate an explanation on why or why not.
If not, how can I make sure that the passed in pointer stays valid and keeps pointing to the modified Settings
value, at the same place in memory?
Upvotes: 0
Views: 1218
Reputation: 42592
Unbox the value
Modify the settings in place
Make sure that the Settings don't get deallocated
It's already been deallocated at step (1): when you deref'd it, you moved the Settings struct out of the Box, and in doing so deallocated the box.
I don't understand why you go through all this mess (or why you pass unsafe pointers to a safe non-extern function).
// create a box from the pointer
let mut settings = unsafe { Box::from_raw(ptr) };
// mutate the value
settings.vec.push(123);
settings.leak();
would work fine and not dealloc anything. Though it's still risky and unnecessary to get a handle on a Box
if the pointer is only borrowed (which it seems to be here since the settings are never returned.
A much better way would be to just create a borrow of the settings vec:
let v = unsafe { &mut (*ptr).vec };
v.push(123);
Or possibly the settings struct if you also need to update the index:
let settings = unsafe { &mut (*ptr) };
settings.vec.push(123);
Upvotes: 2
Reputation: 42786
You can achive the mutation by just dereferencing the pointer in an unsafe block:
pub struct Settings {
pub vec: Vec<usize>,
pub index: usize,
}
pub fn add_to_settings_vec(ptr: *mut Settings) {
// mutate the value
unsafe {(*ptr).vec.push(123)};
}
fn main() {
let mut s = Settings {
vec: vec![],
index: 10,
};
add_to_settings_vec(&mut s as *mut Settings);
println!("{:?}", s.vec);
}
Upvotes: 1