1 pontos por GN⁺ 2 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • Excluir Rust apenas pela existência de unsafe e considerar apenas o Fil-C como seguro ignora o alcance real de aplicação do software e os compromissos técnicos
  • O Fil-C transforma acessos incorretos à memória em C/C++ em pânico, mas isso vem com custos como incompatibilidade de ABI, degradação de desempenho de várias vezes em alguns casos e adoção de GC
  • Nos cerca de 5 milhões de linhas de código Rust do Android, foi encontrada 1 potencial vulnerabilidade de segurança de memória corrigida antes do lançamento, estimada em 0,2 por milhão de linhas, mais de 1.000 vezes abaixo dos cerca de 1.000 casos históricos de C/C++
  • Não é preciso escolher apenas entre uma tecnologia que bloqueia 99,9% dos problemas em todos os programas e outra que bloqueia 100% dos problemas em 90% dos programas; para softwares em que é difícil aceitar as restrições do Fil-C, alternativas como Rust são mais adequadas
  • Segurança de memória deve ser avaliada junto com desempenho, ABI, GC e prevenção de corrida de dados; se Rust for criticado como insuficiente, ao menos o mesmo critério deve ser aplicado a C/C++ comum e ao Zig sem Fil-C

Rust e o modelo de responsabilidade das linguagens de sistemas tradicionais

  • A discussão sobre segurança de memória em linguagens de programação de sistemas sem GC tem se concentrado principalmente na diferença entre os modelos de responsabilidade de Rust e C/C++/Zig
    • Rust tenta impedir a compilação de programas que possam causar problemas de segurança de memória, aceitando o custo de rejeitar até alguns programas que poderiam ser seguros
    • unsafe é uma válvula de escape que permite contornar algumas garantias, como ao autorizar desreferenciação de ponteiros brutos
    • Linguagens da família C deixam a maior parte das garantias de segurança de memória nas mãos do programador
  • Embora existam diferenças no nível de suporte entre linguagens, como RAII e smart pointers em C++ e defer em Zig, elas não impedem por princípio o acesso incorreto à memória em si

A opção adicional trazida pelo Fil-C

  • O Fil-C oferece uma nova abordagem para executar código C e C++ com segurança de memória
    • Quando ocorre um acesso incorreto à memória, como acesso fora dos limites ou uso após liberação, ele gera pânico
    • Combina GC com InvisiCaps, que rastreia a memória que os ponteiros podem acessar
  • Também foi proposto para Zig um novo modo de compilação inspirado no Fil-C
  • Se alguns projetos populares em C/C++ passarem a oferecer releases compiladas com Fil-C, pode haver mais opções para reduzir vulnerabilidades de segurança de memória

O critério que considera Rust inseguro

  • O desenvolvedor do Fil-C vem avaliando no Twitter que Rust não é uma linguagem segura em memória porque unsafe permite contornar algumas garantias
  • O desenvolvedor de Zig, Andrew Kelley, também descreveu no título de uma issue o modo inspirado no Fil-C como um modo de compilação “realmente seguro em memória, ao contrário de Rust”
  • Algumas discussões chegam a exigir que, se usuários de Rust realmente valorizam segurança de memória, deveriam abandonar Rust e promover o Fil-C, que seria mais seguro
  • Esse critério compara Rust e Fil-C sem considerar os custos práticos do Fil-C e adota uma postura semelhante à crítica de fanatismo que a comunidade Rust frequentemente recebe

Restrições de aplicação do Fil-C

  • Fil-C não é um substituto drop-in sem custo
    • Não é compatível em ABI com programas compilados sem Fil-C
    • Em alguns cenários pode ser várias vezes mais lento
    • Introduz GC
  • Em programas como utilitários simples, onde a perda de desempenho é difícil de perceber ou não há necessidade de linkagem dinâmica, essas restrições podem não ser decisivas
  • Por outro lado, há muitos projetos populares que não podem aceitar GC e incompatibilidade de ABI, e programas aos quais o Fil-C em sua forma atual é difícil de aplicar frequentemente se encaixam bem em Rust

Dados reais de vulnerabilidades em código Rust

  • Ainda não há muitos dados para julgar a segurança prática de Rust, mas não têm sido encontradas muitas vulnerabilidades exploráveis de segurança de memória em software Rust
  • Nos mais de 5 milhões de linhas de código Rust do Android, foi encontrada 1 potencial vulnerabilidade de segurança de memória, corrigida antes do lançamento
    • A densidade estimada de vulnerabilidades é de 0,2 por milhão de linhas
    • Os dados históricos de C/C++ no Android são de cerca de 1.000 por milhão de linhas
    • A densidade no código Rust está sendo observada como mais de 1.000 vezes menor que em C/C++
  • Os números podem variar de projeto para projeto, mas isso serve como evidência de que, em ambientes reais, Rust reduz fortemente o risco de introdução de problemas de segurança de memória

Por que não é preciso escolher apenas um

  • A escolha hipotética entre uma tecnologia que bloqueia 99,9% dos problemas em todos os programas e outra que bloqueia 100% dos problemas em 90% dos programas mostra que tanto o alcance de aplicação quanto o nível de prevenção importam
  • As proporções reais são desconhecidas, mas não é necessário escolher apenas uma das duas abordagens
    • Projetos em C/C++/Zig que aceitem os compromissos podem oferecer binários em Fil-C
    • Softwares que não podem usar Fil-C podem ser escritos em linguagens que eliminem totalmente ou em grande parte o risco de vulnerabilidades de segurança de memória

Por que escolher Rust mesmo podendo usar GC

  • É razoável usar Rust mesmo quando existem opções baseadas em GC, como Go ou Fil-C
  • Programas que podem ser escritos em linguagens com GC geralmente não precisam de unsafe, e programas que precisam de unsafe geralmente não podem usar GC
  • Pode-se avaliar como mais importantes do que um pequeno risco de segurança de memória outras garantias e recursos da linguagem, como prevenção de corrida de dados
  • Fil-C transforma vulnerabilidades de segurança de memória existentes em C/C++ em travamentos
    • Isso é melhor do que vulnerabilidades de segurança, mas se a densidade histórica de cerca de 1.000 por milhão de linhas continuar a mesma, ainda restariam muitos travamentos a corrigir
    • No passado, também houve vulnerabilidades de segurança em que a capacidade de fazer um programa travar podia ser explorada por atacantes

Um critério consistente para segurança de memória

  • Se nem mesmo as 0,2 ocorrências por milhão de linhas em Rust forem aceitáveis, então a mesma crítica — ou uma ainda mais rigorosa — deve ser aplicada a C/C++ comum e ao Zig sem Fil-C
  • Permitir alternativas menos seguras que Rust e rejeitar apenas Rust por causa de unsafe mostra uma aplicação inconsistente do absolutismo da segurança de memória

1 comentários

 
GN⁺ 2 시간 전
Comentários no Lobste.rs
  • A fala de Andrew Kelly que o OP parece ter recebido mal é que o Zig consegue compilar até mesmo dependências inteiras em C/C++ em executáveis completamente memory-safe, sem escapatória, com custo de desempenho de cerca de 1 a 6 vezes dependendo da frequência de rastreamento de ponteiros
    O autor tomou isso como um ataque ao Rust e, no fim do texto, ataca o Zig, mas o Fil-C e o novo modo de build do Zig são contribuições positivas para o ecossistema e oferecem pontos de projeto e trade-offs diferentes dos do Rust
    Interpreto isso como significando que, se você seguir a programação orientada a dados preferida pela equipe do Zig, o custo de desempenho pode cair para perto de 1x

    • O autor estava respondendo ao título “introdução de um modo de compilação inspirado no Fil-C, realmente memory-safe ao contrário do Rust” e a um post no Twitter do desenvolvedor do Fil-C
      Não é absurdo ler isso como desnecessariamente provocativo, e Andrew depois mudou o título para algo menos inflamado
  • Ao contrário do normal, quando uma zombaria leve de “a sua linguagem não é memory-safe” foi direcionada a eles, a escala da reação dos desenvolvedores Rust foi considerável
    Eu também gosto muito de Rust, mas é preciso receber isso com mais imparcialidade

    • Dizer que “Rust é bastante memory-safe, mas o Fil-C é mais seguro nesse aspecto” não parece muito controverso e soa factual
      Indo além, o C formalmente verificado do seL4 é ainda mais seguro
    • Como priorizo programas corretos e tento evitar ao máximo escrever código que não seja assim, paradoxalmente prefiro Rust a Zig
      O Zig tem as vantagens de facilitar encerrar corretamente em caso de falha de alocação de memória e de compilar rápido
      Não sei se o Fil-C é mais memory-safe que Rust, mas para meu uso a incompatibilidade com garbage collector e com a ABI de C é um obstáculo decisivo
      Dá para evitar condições de corrida tornando tudo single-threaded e obter memory safety colocando um garbage collector, mas gosto que o Rust ofereça as duas coisas sem esses dois compromissos
  • Como valorizo muito memory safety, o Fil-C e a implementação da ABI do Fil-C no Zig são escolhas naturais
    Em projetos Rust com dependências em C, as garantias de segurança enfraquecem; também é possível usar só Rust puro, mas isso é incômodo
    O Rust também deveria implementar a ABI do Fil-C para poder buildar dependências em C com segurança e ligá-las ao Rust, e não entendo por que isso seria controverso

    • O Rust já tem o interpretador Miri, que verifica se código Rust inseguro preserva as garantias do Rust seguro
      Se algo parecido for implementado, eu gostaria que fosse usado como recurso auxiliar para melhorar código FFI apenas em builds de debug
      Colocar um garbage collector e verificar todas as operações em runtime não serve para todos os usos
  • Antes de descartar o Fil-C como algo apenas para utilitários simples, vale assistir à apresentação sobre Fil-C na conferência Software Should Work
    O apresentador fez a palestra em um notebook Linux com o espaço de usuário inteiro e até o OpenOffice Impress montados com Fil-C
    Pode não ser adequado para alguns programas C/C++, mas não parece uma tecnologia de brinquedo tanto quanto o autor imagina

  • Venho de Python, então memory safety era uma premissa básica, e escolhi Rust por três motivos
    Primeiro, ele permite garantir correção em tempo de compilação com um sistema de tipos forte, e a memory safety obtida com #![forbid(unsafe_code)] e auditoria de dependências via cargo-geiger é a expressão menos interessante disso
    Segundo, ele oferece um ecossistema que facilita escrever o código com segurança uma vez e compartilhá-lo entre várias linguagens e ambientes de execução
    Terceiro, há açúcar sintático que facilita escrever código de alto nível, como o try!(x) da época
    O Zig e o Fil-C não parecem atender à capacidade de fazer o compilador capturar erros lógicos codificando invariantes no sistema de tipos com typestate pattern ou newtypes
    A incompatibilidade de ABI do Fil-C também é um problema ao escrever módulos compilados com segurança para runtimes existentes, como o CPython em hospedagem web compartilhada

    • No Zig também dá para fazer typestate pattern e codificação de tipos para várias restrições, e em alguns aspectos o comptime é mais expressivo que o Rust
      Há trade-offs em tempo de compilação, verbosidade e no fato de a maior parte do ecossistema não tentar chegar a esse nível, mas na prática é possível e bem interessante
  • Fico curioso sobre por que uma tecnologia como o Fil-C não surgiu 20 anos atrás

    • No mundo dos mainframes, problemas de segurança envolvendo compartilhamento e marcação de ponteiros e permissões baseadas em capabilities vêm sendo alertados há décadas
      Mas ninguém queria pagar esse preço em CPU ou memória, isto é, em custo
    • Fiz uma pergunta parecida ao Filip alguns meses atrás e recebi a seguinte resposta
      Entre 2004 e 2018, a ideia existia, mas ele achava que a própria noção de um C memory-safe era tola; entre 2018 e 2023, mudou de ideia, mas não encontrou um jeito de alcançar compatibilidade extrema
      Entre 2023 e o início de 2024, o Fil-C inicial tinha compatibilidade e desempenho muito inferiores, e no fim de 2024 o avanço do InvisiCaps trouxe a compatibilidade alta atual e desempenho razoável
      O que o fez mudar de ideia por volta de 2018 foi observar que variantes de C usadas em GPU são uma forma simples de C memory-safe
    • Há 20 anos, os computadores eram mais lentos e havia muito mais sensibilidade ao custo da segurança
  • Se interpretarmos da forma mais generosa a afirmação de que “se o pessoal do Rust realmente se importa com memory safety, deveria apoiar o Fil-C, que é mais seguro, e abandonar Rust”, isso significaria que agora que o Fil-C existe deveríamos parar de tentar reescrever o mundo em Rust, voltar para C/C++ e manter o ecossistema unificado de bibliotecas como antes
    Mesmo que bibliotecas Rust possam ser usadas em C/C++, há desenvolvedores que não querem isso, então a lógica é que, se usuários de Rust reconhecerem a solução melhor e desistirem, a fragmentação desaparece
    Mas o Fil-C tem trade-offs que o Rust não tem: garbage collector e suporte apenas a x86-64 Linux
    Além de memory safety, Cargo e a ausência de um namespace global são razões importantes para usar Rust, e é lamentável que a fragmentação entre comunidades de linguagens esteja enredada em uma guerra cultural mais ampla
    Eu só quero fazer bibliotecas que qualquer um use de bom grado

    • Será que C e C++ por si só já não são um ecossistema fragmentado?
      Entre desenvolvedores C pode haver quem não queira bibliotecas C++, e agora existem até Zig e Odin, então mesmo que o Rust desapareça a fragmentação continua
      Fico me perguntando se o Rust cria um tipo especialmente diferente de fragmentação
    • Eu também quero um mundo em que todos usem bibliotecas satisfeitos, e estou desenvolvendo um transpilador de alto nível Rust→Zig que preserva genéricos com comptime
      Como Rust codifica mais restrições, ele é a linguagem ideal como origem