CEVIU Logo
Voltar

Reprodutibilidade em builds de WebAssembly: desafios técnicos e soluções no Anubis

Aprofundamento CEVIU

Aprofundamento

O Anubis não é só mais um projeto WebAssembly: ele expõe, em tempo real, as rachaduras entre a teoria da reprodutibilidade e a prática dos compiladores modernos. A equipe não está lidando com um único ponto de falha, está enfrentando uma cadeia de dependências frágeis: clang que chama wasm-opt do $PATH sem avisar, wasm2js cuja saída varia entre distros Linux e Homebrew, e um LLVM que gera código sensível ao layout de memória (até 29 bytes de diferença por build). Isso não é um bug isolado. É o reflexo de como ferramentas como WASI SDK, Binaryen e Clang ainda operam com pressupostos implícitos, como 'exceções WebAssembly estão disponíveis' ou 'o endereço de memória não afeta a ordem de blocos try/catch'. Essa fragilidade se agrava no contexto de proof of work: se o mesmo módulo Wasm produz checksums diferentes em x86_64 e arm64, o sistema perde validade criptográfica. A solução adotada, empacotar wasm2js como Wasm, fixar toolchain, desligar ASLR e gerar checksums por arquitetura, é pragmática, mas revela um fato técnico incômodo: reprodutibilidade cross-arch ainda depende de contornos, não de padrões.

A situação ganha peso com o lançamento oficial do WebAssembly 3.0 como padrão W3C em setembro de 2025. O WasmGC, exceções nativas e suporte a 64-bit memory são agora parte da especificação, mas não são implementados de forma idêntica em todos os runtimes. Wasmer 6.0 atinge 95% da velocidade nativa, mas seu wasm-opt pode ter comportamento diferente do do Wasmtime, que tem status de Core Project da Bytecode Alliance. E o WASI Preview 2.11 (abril/2026) é estável, mas o Preview 3, com threads e async nativo, ainda está em desenvolvimento. Ou seja: o ecossistema está maduro o suficiente para produção (41% das organizações já usam Wasm em produção), mas não uniforme o suficiente para garantir builds idênticos em qualquer máquina.

O que mudou

Em março de 2026, a CEVIU reportou um bug de hardware no RocksDB que expôs como até instruções de CPU (RDSEED) podem comprometer determinismo, um alerta sobre fontes inesperadas de não-reprodutibilidade. Agora, em junho de 2026, o Anubis mostra que o problema migraram para o nível de toolchain: não é mais o hardware, mas sim o clang, o wasm-opt e o próprio WASI SDK que introduzem variação. Antes era 'aleatoriedade acidental'; agora é 'não-determinismo estruturado', embutido em otimizações, layout de memória e extensões ativadas por padrão (como WebAssembly Exceptions). A mudança crítica é que a equipe deixou de confiar em ferramentas de sistema (wasm2js do apt) e passou a embarcar binários compilados com wasi-sdk, um salto de gestão de dependência para gestão de runtime.

Por que isso importa

Builds reprodutíveis não são um luxo de auditores: são um requisito de segurança para qualquer sistema que use Wasm como camada de execução confiável, como proof of work, plugins de navegador ou funções serverless. Se dois desenvolvedores compilarem o mesmo código-fonte e obtiverem módulos Wasm com hashes diferentes, não há como verificar se o binário distribuído corresponde ao código aberto. Isso mina a confiança em atualizações, impede auditorias independentes e abre brechas para supply chain attacks. No caso do Anubis, a falha não é apenas técnica: é conceitual. Um sistema que promete 'mesma lógica cliente/servidor via Wasm' perde credibilidade se essa mesma lógica não for verificável bit a bit. E isso afeta diretamente a experiência do desenvolvedor (DX): quando o CI falha porque o wasm-opt do Ubuntu 24.04 não suporta exceptions, o time gasta horas debugando toolchain, não código.

Linha do tempo

  1. Bug de hardware no RocksDB expõe falha na aleatoriedade de RDSEED, alertando sobre fontes inesperadas de não-determinismo

  2. CEVIU analisa como extensões de linguagem e comportamentos não padronizados dificultam portabilidade entre compiladores C

  3. Anubis implementa estratégias para builds reprodutíveis em WebAssembly, confrontando não-determinismo no clang, wasm-opt e layout de memória

Perguntas frequentes

Por que o clang chama wasm-opt automaticamente e isso quebra reprodutibilidade?

O clang usa wasm-opt durante o linking para otimizar o bytecode Wasm gerado. Mas ele pega a versão instalada no $PATH, não a que você quer. Se sua máquina tem uma versão antiga (sem suporte a WebAssembly Exceptions), o processo falha ou gera saída inconsistente. Isso transforma uma ferramenta de otimização em fonte de não-determinismo.

O que significa 'builds determinísticos dentro da arquitetura, mas não entre elas'?

Significa que um build feito duas vezes no mesmo x86_64 sempre gera o mesmo hash. Mas um build em x86_64 e outro em arm64, mesmo com o mesmo código e flags, podem diferir, por causa de como o LLVM ordena blocos try/catch com base em ponteiros. É um bug conhecido no LLVM, não resolvido.

Por que empacotar wasm2js como Wasm resolve o problema?

Porque elimina a dependência de versões do sistema. Ao compilar wasm2js com wasi-sdk e incluir esse binário no repositório, a equipe garante que todos usam exatamente a mesma versão, com as mesmas flags, mesmo target e mesmo suporte a extensões. É controle total sobre a toolchain.

Qual é o papel do WASI nisso tudo?

O WASI define como o Wasm interage com o sistema, mas sua evolução (Preview 2.11 → Preview 3) ainda é fragmentada. Ferramentas como wasi-sdk assumem funcionalidades do WASI que nem todos os runtimes suportam igualmente. Isso cria divergências silenciosas entre ambientes, mesmo com o mesmo código-fonte.

Fontes

Avalie este artigo:
Compartilhar:
Categoria
CEVIU Web Dev
Publicado
19 de junho de 2026
Editoria
CEVIU Web Dev

Quer receber mais sobre CEVIU Web Dev?

Conteúdo curado diariamente, direto no seu e-mail.

Conteúdo curado diariamenteDiversas categoriasCancele quando quiser