Lançamento do Rust 1.96. Avaliação da adequação do Rust para criar firmware para microcontroladores

Foi lançado o Rust 1.96, uma linguagem de programação inicialmente desenvolvida pela Mozilla, mas agora mantida por uma organização não governamental independente, a Rust Foundation. A linguagem é focada na segurança de memória e oferece ferramentas para alcançar alto paralelismo na execução de tarefas, sem a necessidade de um coletor de lixo ou de tempo de execução (o tempo de execução se resume à inicialização básica e à manutenção da biblioteca padrão).

Os métodos de gerenciamento de memória no Rust visam eliminar erros ao manipular ponteiros e proteger contra problemas que surgem devido ao trabalho de baixo nível com a memória, como o acesso à memória após a liberação, a desreferenciação de ponteiros nulos, estouro de buffer, entre outros. Para a distribuição de bibliotecas, a construção e o gerenciamento de dependências, o projeto tem evoluído com o gerenciador de pacotes Cargo. O repositório crates.io é suportado para o armazenamento de bibliotecas.

A manipulação segura da memória em Rust é garantida em tempo de compilação através da verificação de referências, rastreamento de propriedade de objetos, controle do tempo de vida dos objetos (escopos) e avaliação da correção do acesso à memória durante a execução do código. Rust também oferece mecanismos para proteção contra estouros inteiros, exige a inicialização obrigatória de valores de variáveis antes do uso, trata erros de forma superior na biblioteca padrão, aplica o conceito de referências e variáveis imutáveis (immutable) por padrão e oferece uma forte tipagem estática para minimizar erros lógicos.

Principais novidades:

  • Foi adicionado o módulo range com a implementação de novos tipos, desenvolvidos para substituir os tipos obsoletos Range, RangeInclusive, RangeToInclusive e RangeFrom, permitindo armazenar intervalos em estruturas Copy. O tipo Range define intervalos, limitados por um valor mínimo e um máximo permitido (mas não incluindo-o), o tipo RangeFrom define números a partir de um valor especificado, enquanto o tipo RangeInclusive inclui os valores do intervalo especificado, com ambas as extremidades. Em futuras versões, os tipos RangeFull e RangeTo serão apresentados, e a implementação antiga será movida para core::range::legacy::*, com a sintaxe 'N..M' sendo convertida para a nova variante de tipos.

    Os novos tipos se destacam por implementarem o trait IntoIterator em vez do trait Iterator, ou seja, em vez de um iterador embutido, definem como um tipo é convertido em um iterador. Essa abordagem permite o uso da operação de cópia com os novos tipos (o trait Copy, que indica que valores desse tipo podem ser duplicados através de cópia simples), que anteriormente não eram acessíveis devido à incompatibilidade com tipos que possuem iteradores embutidos.
    Por exemplo, os novos tipos permitem armazenar as extremidades de um fatiamento em uma estrutura que é completamente copiada sem a necessidade de salvar separadamente os valores inicial e final:

    use core::range::Range;

    #[derive(Clone, Copy)]
    pub struct Span(Range);

    impl Span {
    pub fn of(self, s: &str) -> &str {
    &s[self.0]
    }
    }

  • Novos macros "assert_matches!" e "debug_assert_matches!" foram adicionados, que verificam se um valor corresponde ao padrão especificado e encerram a execução em caso de divergência. Diferente das expressões "assert!(matches!(..))" e "debug_assert!(matches!(..))", os novos macros fornecem informações de depuração com os valores que causaram a falha. Para evitar sobreposições com macros de terceiros que têm nomes semelhantes, os novos macros exigem a importação explícita da biblioteca "core::assert_matches."

    use core::assert_matches;

    fn get_random_number() -> u32 {
    4
    }

    fn main() {
    assert_matches!(get_random_number(), 1..=6);
    }

  • Na construção para a plataforma de destino WebAssembly, a passagem da opção «—allow-undefined» para o vinculador, que permitia a ligação em presença de símbolos indefinidos que eram convertidos em importação do módulo «env», foi interrompida. Na construção para WebAssembly, todos os símbolos relacionados à ligação agora devem ser definidos obrigatoriamente por padrão. Para restaurar o comportamento anterior, é possível usar a variável de ambiente «RUSTFLAGS=-Clink-arg=—allow-undefined» ou a expressão ‘#[link(wasm_import_module = «env»)]’ no código.
  • Uma nova leva de APIs foi traduzida para a categoria estável, incluindo estabilizações de métodos e implementações de traits:
    • assert_matches!
    • debug_assert_matches!
    • From para AssertUnwindSafe
    • From para LazyCell
    • From para LazyLock
    • core::range::RangeToInclusive
    • core::range::RangeToInclusiveIter
    • core::range::RangeFrom
    • core::range::RangeFromIter
    • core::range::Range
    • core::range::RangeIter
  • No gerenciador de pacotes Cargo, a vulnerabilidade CVE-2026-5223, que pode ser utilizada para sobrescrever o código-fonte de outro pacote crate no cache local de pacotes do mesmo repositório através de manipulações com links simbólicos dentro do crate, foi corrigida. A vulnerabilidade se manifesta apenas ao trabalhar com repositórios de pacotes de terceiros e não afeta usuários do repositório crates.io, pois upload de pacotes com links simbólicos é proibido no crates.io.

Além disso, vale mencionar a publicação (PDF) dos resultados da análise da adequação da linguagem Rust para o desenvolvimento de firmware para microcontroladores e sistemas embarcados com recursos limitados.
A pesquisa foi realizada pela STMicroelectronics com a participação de várias universidades europeias. Duas equipes de desenvolvimento isoladas foram incumbidas de implementar a mesma firmware para os microcontroladores STM32U585AI com núcleo Arm Cortex-M33. A primeira equipe desenvolveu a firmware em C, e a segunda em Rust.

Os testes realizados não apontaram vantagens significativas no uso da linguagem C em vez de Rust no desenvolvimento de firmwares para microcontroladores quando comparados o consumo de memória e desempenho. Além disso, o uso do runtime do sistema escrito em Rust do projeto aberto Ariel OS permitiu alcançar um consumo de memória no projeto em Rust inferior ao da implementação em C, que utilizava a pilha tradicional para desenvolvimento de firmwares baseada na biblioteca newlib.

O tamanho do firmware resultante foi de 84100 bytes no projeto em Rust e 76744 bytes no projeto em C (10% menor), mas o consumo de memória RAM no firmware em Rust foi significativamente menor — 24640 bytes contra 42608 bytes. Em termos de desempenho, durante os testes dos protótipos iniciais, desenvolvidos em 6 semanas, a implementação em Rust superou em duas vezes a implementação em C, mas ambas as implementações ficaram bem abaixo do desempenho máximo estimado. Após 4 semanas dedicadas à otimização, ambas as implementações alcançaram resultados aproximadamente iguais, próximos ao máximo calculado.



Fonte: opennet.ru
Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster