On tricky problem impossible to do without unsafe blocks, is holding in a struct references to something owned by an other attribute of this struct.
However, with unsafe blocks it's quite easy, one can do something like:
struct Foo {
bar: &'static str,
foo: String
}
impl Foo {
pub fn new(s: String) -> Foo {
Foo {
bar: unsafe { ::std::mem::transmute(&s[..]) },
foo: s
}
}
}
Here is the question: provided no method of the struct Foo
previously defined gives &mut
access to it (the struct will thus never be modified after creation), knowing that the data of String
is heap-allocated, is this code actually safe (according to rust meaning of "safe")? If not, what are the situations where a problem may arise?
&mut
access is not (that) important. What's important is that the String
is never changed (at least without the &'static str
also being changed), other data can change for all we care. Besides, if a &mut
would allow third party code to change the string, then they could also change it without a pointer, via inherited mutability:
let x = Foo::new(string);
let mut x = x;
x.foo = other_string;
println!("{}", x.bar); //
So at the very least you must keep the attribute private and audit all code in the same module (not just the impl Foo
!). There's another problem though:
If you ever hand out the &'static str
, then yes, it is unsafe:
let x = Foo::new(string);
let s: &'static str = obtain_str(x);
drop(x);
println!("{}", s); // use after free
So what you can do safely with this kind of self-reference is very limited. The second problem could, maybe, be prevented with appropriate use of lifetimes, but this gets into the area where I'm not willing to accept safety without an elaborate semi-formal argument.
For the use cases I imagine, it is probably easier to bite the bullet and stay away from unsafe
.