Desreferenciando Ponteiros Brutos
Criar ponteiros é seguro, mas desreferenciá-los requer unsafe:
fn main() {
let mut s = String::from("cuidado!");
let r1 = &mut s as *mut String;
let r2 = r1 as *const String;
// SEGURANÇA: r1 e r2 foram obtidos através de referências e logo é
// garantido que eles não sejam nulos e sejam propriamente alinhados, os objetos
// cujas referências foram obtidas são válidos por
// todo o bloco inseguro, e eles não sejam acessados tanto através das
// referências ou concorrentemente através de outros ponteiros.
unsafe {
println!("r1 é: {}", *r1);
*r1 = String::from("oh-oh");
println!("r2 é: {}", *r2);
}
// INSEGURO. NÃO FAÇA ISSO.
/*
let r3: &String = unsafe { &*r1 };
drop(s);
println!("r3 é: {}", *r3);
*/
}
É uma boa prática (e exigida pelo guia de estilo do Android Rust) escrever um comentário para cada bloco unsafe explicando como o código dentro dele satisfaz os requisitos de segurança para a operação insegura que está fazendo.
No caso de desreferência de ponteiros, isso significa que os ponteiros devem ser válidos, ou seja:
- O ponteiro deve ser não nulo.
- O ponteiro deve ser desreferenciável (dentro dos limites de um único objeto alocado).
- O objeto não deve ter sido desalocado.
- Não deve haver acessos simultâneos à mesma localização.
- Se o ponteiro foi obtido lançando uma referência, o objeto subjacente deve estar válido e nenhuma referência pode ser usada para acessar a memória.
Na maioria dos casos, o ponteiro também deve estar alinhado corretamente.
A seção “NÃO É SEGURO” dá um exemplo de um tipo comum de bug UB: *r1 tem o tempo de vida 'static, então r3 tem o tipo &'static String, e portanto sobrevive a s. Criar uma referência a partir de um ponteiro requer muito cuidado.