"Double memory free", mais uma vez rust em ação
Um bug muito conhecido que aparece em linguagem que atuam em um mais baixo nível como por exemplo a dupla C/C++.
O bug
Imagine que temos uma variável x
, ela é um inteiro sem sinal de 32 bits (pra quem gosta de especificidade) com o valor 10
:
// pseudo código
unsigned int x = 10;
Agora neste mesmo pensamento, temos uma variável y
, ela recebe x
:
// pseudo código
...
unsigned int y = x;
resultando no seguinte código:
unsigned int x = 10;
unsigned int y = x;
Ao fazer essa associação, a variável y
está apontando para o mesmo endereço de memória da variável x
, então após algum código eu preciso limpar essas variáveis da memória, então eu chamo uma função que faz essa limpeza para a variável y
, e logo após chamo a mesma função para a variável x
, o problema é que as duas apontam para o mesmo endereço de memória o que significa que ao tentar limpar a variável y
a variável x
não existe mais.
Então é ai onde o bug acontece, pois eu vou estar tentando limpar um endereço que não existe mais.
Bom, o foco aqui não é falar sobre o bug em si, mas sim como o rust faz para nos proteger de cair nessa silada.
Assumindo que você compreendeu como o bug acontece vamos para nosso próximo tópico.
Como o rust nos protege desse bug?
Bom, no rust as coisas funcionam um tanto quanto diferentes, deixe me lhe mostra com código:
no exemplo acima nós temos uma variável x
que é igual a 10
, e logo abaixo criamos uma variável y
que recebe x
.
Ao rodar o programa temos o seguinte resultado
Os valores são iguais, mas os endereços na memória são diferentes, isso acontece porque no caso de inteiros e outros tipos no rust, uma cópia dos dados é feita. então, a variável y
recebe uma cópia da variável x
.
Nesse caso o bug não acontece, pois são duas variáveis distintas.
Agora vamos dar uma olhada em uma situação interessante:
esse código aparentemente deve funcionar normalmente correto?
mas ao executarmos veja só o output que temos:
Obtivemos um erro.
Deixe me explicar o que aconteceu.
Quando usamos o tipo String
, ao fazer essa associação de s2 = s1
a variável s2
irá apontar para o mesmo endereço de memória que a variável s1
está apontando.
Por padrão, em tempo de execução ao uma variável sair do seu escopo o rust automaticamente libera aquele espaço para nós, nesse exemplos temos duas variáveis apontando para o mesmo endereço
Então quando o escopo em que as variáveis s1
e s2
estão, em teoria, o rust deveria limpar esses valores, mas caso ele limpasse a variável s2
a variável s1
não existiria mais, então ele iria estar tentando liberar um endereço que não existe mais.
então para nossa segurança em tempo de compilação, após a atribuição da variável s2
para a variável s1
o compilador considera s1
inválida e não permite o uso dela após essa atribuição, nos prevenindo de causar um possível bug em nosso software.
Rust will never automatically create “deep” copies of your data. Therefore, any automatic copying can be assumed to be inexpensive in terms of runtime performance.
Espero que tenha gostado desse artigo, sinta-se livre para responder, estamos todos aprendendo! 🤩