image

Acesse bootcamps ilimitados e +650 cursos

50
%OFF
Article image
Franklyn Sancho
Franklyn Sancho06/07/2023 13:53
Compartilhe

Você sabia que existe um modo inseguro na linguagem rust?

    Resumo

    Hoje eu quero falar sobre o unsafe rust, uma parte da linguagem rust que nos permite escrever códigos que podem comprometer a segurança de memória e concorrência que o Rust nos garante. Mas se ele compromete a segurança, por que precisamos dele?

    Rust , segurança e borrow check

    Antes de tudo, precisamos entender que o Rust é uma linguagem muito segura e performática, essa segurança é garantida pela forma como ela gerencia a memória, conhecida como ownership, uma abordagem diferente de outras linguagens que usam o garbage collector ou alocação explicita.

    Além dessa abordagem, o rust dispõe de outras garantias de segurança, como empréstimo, lifetimes e traits, que são verificadas em tempo de compilação por meio de um sistema chamado borrow check. Esse sistema verifica se o código respeita as regras de propriedade e empréstimo de valores, evitando erros de acesso inválidos a ponteiros, uso após liberação, corrupção de dados e etc.

    As regras do Ownership:

    1. Cada valor tem uma variável que é sua dona 

    2. Só pode haver uma dona por vez 

    3. Quando a dona sai do escopo, o valor é apagado

    Quando usar o Rust Unsafe

    No entanto, as vezes precisamos escrever códigos que o compilador não consegue entender ou verificar, ou seja, a garantia de segurança fica nas mãos do desenvolvedor. Para que fique ainda mais claro, ativar o modo unsafe é como se o rust dissesse assim: “Ok, a segurança desse negócio está em suas mãos”. Mas em quais momentos isso é necessário?

    1. Criar uma variável global, ou seja, que pode ser modificada em qualquer parte do código (e não apenas dentro do seu escopo); 
    2. Interagir com código externo e usar instruções de baixo nível; 
    3. Desreferenciar um ponteiro bruto – obter o valor que ele aponta; 
    4. Implementar uma trait unsafe 
    5. Acessar campos de uma união – um tipo de dado que pode guardar diferentes tipos de valores no mesmo endereço de memória, diferente de uma struct.
    Obs. O rust unsafe não desativa as verificações de segurança do rust, ela apenas nos dá acesso aos recursos que não são verificados pelo compilador.

    Exemplos de uso

    Veja o exemplo dessa aplicação que simula um caixa eletrônico, no primeiro exemplo nós temos uma função main recebendo uma variável total_coins, seu valor é repassado no parâmetro das funções. No segundo exemplo nós temos uma variável global TOTAL_COINS, onde seu valor pode ser usado em qualquer lugar do código

    Sem o rust unsafe

    //sem o modo unsafe,   
    fn main() {
    
    	//a variável está dentro da função 
      let total_coins: f64 = 0.0;
    
    
      println!("Bem vindo ao seu internet banking");
      println!("escolha a sua opção: ");
      println!("1 - Depositar");
      println!("2 - Sacar");
      println!("Insira a sua opção aqui: ");
    
    
      let mut option = String::new();
    
    
      io::stdin().read_line(&mut option).expect("Erro de entrada");
    
    
      if option.contains("1") {
        	//seu valor é passado como argumento
          insert_money(deposit: total_coins)
      } else if option.contains("2") {
        	//seu valor é passado como argumento
          get_money(discredit: total_coins)
      } else {
          println!("Opção inválida")
      }
    }
    

    Com o rust Unsafe

    //criamos uma variável global no escopo global 
    static mut TOTAL_COINS: f64 = 0.0;
    
    
    //a função não tem parâmetro, 
    fn insert_money() {
      unsafe { //chamamos o modo unsafe
          let coins = [2.00, 5.00, 10.00, 20.00, 50.00, 100.00];
    
    
          loop {
              println!("Insira quanto você deseja investir: ");
    
    
              let mut credit = String::new();
    
    
              io::stdin()
                  .read_line(&mut credit)
                  .expect("Falha ao ler entrada");
    
    
              let credit = credit.trim().parse().expect("valor inválidos");
    
    
              if coins.contains(&credit) {
                	//usamos a varivel TOTAL_COINS
                  TOTAL_COINS = credit + TOTAL_COINS;
                  println!("Você inseriu {} e seu saldo é {}", credit, TOTAL_COINS)
              } else if credit == 0.0 {
                  main()
              } else {
                  println!("Ocorreu um erro")
              }
          }
      }
    }
    
    Compartilhe
    Comentários (0)