Funções Inseguras

Chamando Funções Inseguras

Uma função ou método pode ser marcado como unsafe se houver pré-condições extras que você deve respeitar para evitar comportamento indefinido:

extern "C" {
    fn abs(input: i32) -> i32;
}

fn main() {
    let emojis = "🗻∈🌏";

    // Seguro porque os índices estão na ordem correta, dentro dos limites da
    // slice da string, e contido dentro da sequência UTF-8.
    unsafe {
        println!("emoji: {}", emojis.get_unchecked(0..4));
        println!("emoji: {}", emojis.get_unchecked(4..7));
        println!("emoji: {}", emojis.get_unchecked(7..11));
    }

    println!("contador de caracteres: {}", count_chars(unsafe { emojis.get_unchecked(0..7) }));

    unsafe {
        // Comportamento indefinido se abs se comportar mal.
        println!("Valor absoluto de -3 de acordo com C: {}", abs(-3));
    }

    // Não manter o requerimento de codificação UTF-8 viola segurança de memória!
    // println!("emoji: {}", unsafe { emojis.get_unchecked(0..3) });
    // println!("contador caracter: {}", count_chars(unsafe {
    // emojis.get_unchecked(0..3) }));
}

fn count_chars(s: &str) -> usize {
    s.chars().count()
}

Escrevendo Funções Inseguras

Você pode marcar suas próprias funções como inseguras (unsafe) se elas exigirem condições específicas para evitar comportamentos indefinidos.

/// Troca os valores apontadoes pelos ponteiros fornecidos.
///
/// # Segurança
///
/// Os ponteiros precisam ser válidos e corretamente alinhados.
unsafe fn swap(a: *mut u8, b: *mut u8) {
    let temp = *a;
    *a = *b;
    *b = temp;
}

fn main() {
    let mut a = 42;
    let mut b = 66;

    // Seguro porque ...
    unsafe {
        swap(&mut a, &mut b);
    }

    println!("a = {}, b = {}", a, b);
}
This slide should take about 5 minutes.

Chamando Funções Inseguras

get_unchecked, como a maioria das funções _unchecked, é insegura, porque pode criar UB se o intervalo estiver incorreto. abs está incorreto por um motivo diferente: é uma função externa (FFI). Chamar funções externas é geralmente um problema apenas quando essas funções fazem coisas com ponteiros que podem violar o modelo de memória do Rust, mas, em geral, qualquer função C pode ter comportamento indefinido sob quaisquer circunstâncias arbitrárias.

O "C" neste exemplo é o ABI; outros ABIs também estão disponíveis.

Escrevendo Funções Inseguras

Na verdade, não usaríamos ponteiros para uma função swap - isto pode ser feito com referências com segurança.

Observe que o código inseguro é permitido dentro de uma função insegura sem um bloco unsafe. Podemos proibir isso com #[deny(unsafe_op_in_unsafe_fn)]. Tente adicioná-lo e veja o que acontece. Isso provavelmente mudará em uma edição futura do Rust.