1 pontos por GN⁺ 3 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • FFmpeg, que processa mídia em navegadores e infraestruturas de streaming no mundo todo, analisa entradas complexas e não confiáveis, tornando-se uma superfície de ataque importante para a segurança
  • O agente de segurança autônomo da depthfirst encontrou 21 zero-days em cerca de 1,5 milhão de linhas de código C otimizado, com custo de cerca de $1k, ou seja, aproximadamente 10% dos $10k gastos com o Mythos da Anthropic
  • Os achados se espalham por vários componentes, incluindo o TS demuxer, o VP9 decoder e caminhos de processamento de RTP/RTSP/RTMP, e algumas vulnerabilidades ficaram latentes por 15 a 20 anos
  • A vulnerabilidade no AV1 RTP depacketizer levou a um PoC que sobrescreve um ponteiro de função usando apenas um pacote RTP de 183 bytes, sendo alcançável apenas com a execução de ffmpeg -i rtsp://attacker/stream
  • A validação de segurança prática exige não apenas alertas teóricos, mas também entradas reproduzíveis e confirmação de execução, e a análise orientada por agentes pode ser aplicada diretamente para descobrir vulnerabilidades ocultas em grandes bases de código C

Visão geral

  • FFmpeg é um software amplamente distribuído usado para processar mídia em navegadores e na infraestrutura de grandes plataformas de streaming
  • Como é uma biblioteca que analisa continuamente mídia complexa e não confiável, ela é crítica para a segurança e se torna um alvo importante de ataques zero-click
  • O repositório do FFmpeg é composto por cerca de 1,5 milhão de linhas de código C altamente otimizado e analisa centenas de formatos de mídia complexos
  • O FFmpeg passou por mais de 20 anos de fuzzing e auditorias manuais, e recentemente a equipe Google Big Sleep divulgou 13 vulnerabilidades no FFmpeg
  • A Anthropic escaneou o FFmpeg com o modelo Mythos e encontrou alguns problemas de segurança
  • Depois desse trabalho prévio, encontrar novas vulnerabilidades no FFmpeg ficou mais difícil, tornando-o um bom alvo para medir a capacidade de sistemas orientados por agentes de escanear grandes bases de código em profundidade

O agente de segurança da Depthfirst

  • Agentes de programação e agentes de segurança podem usar o mesmo modelo de base, mas seus objetivos são muito diferentes
  • Um agente de programação normalmente recebe tarefas humanas e se concentra em escrever código de aplicação
  • Um agente de segurança assume um papel mais restrito e orientado por objetivo: encontrar problemas de segurança reais e exploráveis em sistemas existentes, sem instruções detalhadas
  • O agente de segurança precisa primeiro entender a arquitetura da base de código, os parsers e handlers de protocolo expostos e os pontos de entrada de dados controlados pelo atacante
  • Depois disso, ele não trata o repositório como um conjunto plano de arquivos, mas acompanha o fluxo de dados a partir do código da superfície de ataque até os componentes relacionados
  • Um agente de segurança prático precisa de guardrails que impeçam inventar condições ausentes, exagerar bugs teóricos ou produzir grande volume de falsos positivos
  • É preciso verificar se o atacante realmente controla a entrada correta, se o caminho vulnerável é alcançável e se a falha suspeita é reproduzível
  • Quando necessário, ele deve identificar ou criar um harness para interagir com o componente-alvo e testar a hipótese de forma concreta
  • O agente de segurança especializado da depthfirst analisa o código em profundidade e testa várias hipóteses em paralelo
  • O resultado não é um relatório teórico nem alertas vagos, mas problemas de segurança confirmados em execução com entradas concretas e reproduzíveis

Resultados encontrados

  • O agente encontrou ao todo 21 zero-days, cobrindo desde o TS demuxer até o VP9 decoder
  • O custo total foi de cerca de $1k, o que equivale a aproximadamente 10% do valor gasto pela Anthropic com o Mythos
  • Comparação de custo: {b:1,10}
  • Vulnerabilidades com CVE atribuído

    • CVE-2026-39210 é um heap buffer overflow no TS demuxer causado pela ausência de verificação de limite de comprimento antes da leitura de dois bytes, introduzido em 2010
    • CVE-2026-39211 é um integer overflow introduzido em 2010 durante um refactor do swscale, em que uma fórmula de fator de tamanho sem limite superior permitia que parâmetros controlados pelo usuário provocassem escalonamentos arbitrariamente grandes
    • CVE-2026-39212 é um stack overflow em ffmpeg_opt.c, no qual arquivos preset podiam acionar recursivamente o parsing de opções sem limite de profundidade, introduzido como regressão em julho de 2025
    • CVE-2026-39213 é um heap buffer overflow no caminho de entrada rawvideo do yuv4mpegenc por falta de validação de dimensões em relação ao tamanho do pacote, introduzido em 2023
    • CVE-2026-39214 é um stack buffer overflow na implementação original de SDT, que escrevia entradas de serviço sem rastrear o espaço restante, introduzido em 2003 e latente por 23 anos
    • CVE-2026-39215 é um heap buffer overflow causado por um erro de lógica em update_mb_info() que faz chamadas posteriores escreverem 12 bytes além do buffer alocado, introduzido em 2012
    • CVE-2026-39216 é um heap buffer overflow em img2enc.c causado pela substituição de um tamanho de croma seguro por um tamanho sem limite baseado em dimensões, introduzido em 2012
    • CVE-2026-39217 é um heap buffer overflow no VP9 decoder causado por uma função de atualização de tamanho refatorada que faz o buffer da tile thread perder a realocação necessária, introduzido como regressão em março de 2025
    • CVE-2026-39218 é um heap buffer overflow no DASH demuxer, que não rejeita valores negativos de duration, fazendo o índice do array de fragmentos se tornar negativo, introduzido em 2017
  • Vulnerabilidades referenciadas por IDs internos de rastreamento

    • DFVULN-127 é um heap buffer overflow em que av1_handle_packet() do RTP AV1 depacketizer ignora o OBU Temporal Delimiter e avança a posição de saída em obu_size, mas não aloca espaço do mesmo tamanho, fazendo com que o OBU seguinte escreva além do limite do buffer
    • DFVULN-126 é um heap buffer overflow em que run_legacy_unscaled() no código graph do swscale trata incorretamente a conversão interlaced YUV420P→NV12 e sobrescreve o Y-plane de destino em 576 bytes
    • DFVULN-125 é um stack buffer overflow em que jpeg_create_header() do RTP JPEG depacketizer monta a seção de quantization-table em um buffer de pilha de 1024 bytes e, após um pacote com qtable_len >= 1024, o AV_WB16 escreve 2 bytes além do fim
    • DFVULN-124 é um heap buffer overflow em que istg_parse_tile_grid() no caminho de overlay AVIF não rejeita uma referência dimg com 0 entradas de tile, provocando uma leitura fora dos limites em uma alocação de heap de 1 byte após wraparound sem sinal
    • DFVULN-123 é um integer overflow em que latm_parse_packet() do RTP LATM depacketizer contorna a verificação de limites com overflow de soma signed 32-bit, fazendo o memcpy ler cerca de 1 GB além do fim do heap buffer
    • DFVULN-122 é um heap buffer overflow em que aac_parse_packet() do RTP MPEG-4 depacketizer aceita AU-headers-length 0, cria uma alocação de 1 byte e depois lê um campo de 4 bytes sem verificar a existência do AU header
    • DFVULN-121 é um heap buffer underflow em que read_seek() do CAF demuxer não verifica o valor de retorno -1 de av_index_search_timestamp() e o usa como índice de array para acessar index_entries[-1]
    • DFVULN-120 é um integer underflow em que ff_read_riff_info() do AVI demuxer recebe size - 4 sem verificar size >= 4, fazendo o tamanho do chunk LIST de 0 virar cerca de 4 GB por underflow e provocando uma alocação de cerca de 2 GB
    • DFVULN-119 é um heap buffer overflow em que um incremento desnecessário em opt_map() no option parser interpreta incorretamente um link-label como índice de arquivo e armazena stream index -1, fazendo um loop posterior ler antes do array AVStream**
    • DFVULN-118 é um heap buffer overflow em que rtsp_read_announce() no caminho de servidor RTSP trata Content-Length negativo como válido e, com um ANNOUNCE remoto e Content-Length: -1, provoca uma escrita fora dos limites em sdp[-1]
    • DFVULN-117 é um heap buffer overflow em que rtmp_calc_swfhash() no cliente RTMP verifica apenas in_size < 3 em vez de in_size < 8, lendo 8 bytes de um buffer com no mínimo 3 bytes
    • DFVULN-116 é um heap buffer overflow em que sdp_parse_line() no parsing de SDP do RTSP calcula strlen(control_url) - 1 em uma string vazia, fazendo size_t dar wrap para SIZE_MAX e causando uma leitura de 1 byte antes do buffer

Do marcador de frame ignorado ao controle do PC

  • Entre os 21 achados, o heap buffer overflow no AV1 RTP depacketizer é alcançável pela rede sem flags especiais
  • Basta a vítima executar ffmpeg -i rtsp://attacker/stream, e um único pacote de 183 bytes pode alterar o fluxo de execução
  • Quando o FFmpeg busca um stream RTSP, o servidor entrega o vídeo codificado como uma sequência de pacotes RTP
  • O AV1 organiza o bitstream em OBUs (Open Bitstream Units), e o formato de payload RTP divide essas OBUs em vários pacotes
  • O depacketizer do FFmpeg é responsável por remontar as OBUs fragmentadas em um elementary stream limpo
  • O Temporal Delimiter (TD) é um pequeno marcador que separa uma temporal unit, ou seja, um frame do próximo frame
  • A especificação determina que o depacketizer deve “ignore and remove” o TD dentro do payload
  • Foi exatamente esse tratamento de “ignore and remove” que se tornou o ponto problemático e foi capturado pelo agente

Causa raiz

  • O depacketizer constrói o pacote de saída de forma gradual, e o cursor pktpos acompanha a próxima posição de escrita dentro de pkt->data
  • pktpos começa no fim atual do pacote
// libavformat/rtpdec_av1.c:199
pktpos = pkt->size;
  • Quando o código percorre os elementos OBU no pacote, todo byte realmente emitido vem precedido por uma chamada a av_grow_packet, que aumenta a alocação de heap de pkt->data
  • A invariante da qual toda a rotina depende é que pktpos nunca deve avançar além do tamanho alocado de pkt->data
  • O código de tratamento do Temporal Delimiter quebra essa invariante
// libavformat/rtpdec_av1.c:250
if ((obu_type == AV1_OBU_TEMPORAL_DELIMITER) ||
    (obu_type == AV1_OBU_TILE_LIST)) {
    pktpos += obu_size;
    rem_pkt_size -= obu_size;
    obu_cnt++;
    continue;
}
  • Ao pular o TD, pktpos avança pela quantidade obu_size declarada pelo atacante, mas não há alocação de memória que sustente esse avanço
  • O ponteiro de entrada buf_ptr também não avança para além dos bytes do TD
  • Com obu_size = 148 no TD, pktpos passa a 148, mas pkt->data ainda pode não estar alocado ou pode ser muito menor que 148 bytes
  • A próxima iteração volta a analisar os próprios bytes do TD, relê o byte de header do TD como o comprimento de um novo OBU e usa o payload como conteúdo do OBU manipulado
  • No próximo OBU normal, o pacote cresce apenas o suficiente para o tamanho desse OBU
// libavformat/rtpdec_av1.c:296
if ((result = av_grow_packet(pkt, output_size)) < 0)
    return result;

// libavformat/rtpdec_av1.c:304 / 336
pkt->data[pktpos++] = *buf_ptr++ | AV1F_OBU_HAS_SIZE_FIELD;
memcpy(pkt->data + pktpos, buf_ptr, obu_payload_size);
  • Se o OBU manipulado tiver 17 bytes, av_grow_packet aloca um buffer de 81 bytes, somando os 17 bytes e o padding de entrada de 64 bytes do FFmpeg
  • A escrita começa em pkt->data[148] e acontece 67 bytes além do fim da alocação
  • Essa falha se torna um heap buffer overflow em que o atacante controla tanto o deslocamento quanto o conteúdo

Forma de exploração

  • Para um overflow controlável ser útil, é preciso haver um alvo interessante logo após o buffer, e o allocator do FFmpeg fornece esse alvo
  • Quando av_grow_packet aloca o buffer de dados do pacote, ele passa por av_buffer_alloc, e essa função aloca em sequência o buffer de dados, a struct de bookkeeping AVBuffer e o AVBufferRef
  • O FFmpeg aloca via posix_memalign com alinhamento de 64 bytes, então um buffer de dados de 81 bytes ocupa um chunk de 128 bytes e a struct AVBuffer fica logo em seguida
  • A struct AVBuffer contém um ponteiro de função usado como callback de liberação
// libavutil/buffer_internal.h
struct AVBuffer {
    uint8_t *data;        // +0
    size_t   size;        // +8
    atomic_uint refcount; // +16
    void (*free)(void *opaque, uint8_t *data); // +24
    void    *opaque;      // +32
    ...
};
  • Considerando o início do buffer de dados, o ponteiro AVBuffer.free fica no deslocamento 152
  • Com obu_size = 148 no TD, a escrita começa em pkt->data[148]
  • O byte de header do TD 0x10 é reinterpretado como comprimento 16, e o header e o payload do OBU manipulado são escritos a partir do deslocamento 148
  • AVBuffer.refcount fica nos offsets 144–147, então permanece antes do ponto de escrita e mantém o valor original 1
  • O exploit embute um terceiro OBU manipulado dentro do payload do TD para acionar mais uma chamada a av_grow_packet
  • Como o buffer foi criado por av_buffer_alloc, e não por av_buffer_realloc, ele não é marcado como realocável, então o FFmpeg segue o caminho de alocar um novo buffer e depois liberar o antigo
// libavutil/buffer.c:209
if (!(buf->buffer->flags_internal & BUFFER_FLAG_REALLOCATABLE) || ...) {
    ret = av_buffer_realloc(&new, size);
    memcpy(new->data, buf->data, ...);
    buffer_replace(pbuf, &new);
    return 0;
}
  • buffer_replace reduz o refcount do buffer antigo de 1 para 0 e chama o callback de liberação
// libavutil/buffer.c:129
if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) {
    b->free(b->opaque, b->data);
}
  • Nesse momento, o ponteiro free sobrescrito é chamado, permitindo controle do instruction pointer
  • Em uma release build, um único pacote RTP de 183 bytes fez o rip assumir o valor 0xdeadbeef
#0  0x00000000deadbeef in ?? ()
rip            0xdeadbeef          0xdeadbeef
#1  buffer_replace (buffer.c:133)
#2  av_buffer_realloc (buffer.c:220)
#3  av_grow_packet (packet.c:151)
#4  av1_handle_packet (rtpdec_av1.c:296)
#5  rtp_parse_packet_internal (rtpdec.c:743)

Escopo de impacto e PoC

  • Ambientes de implantação em que o FFmpeg é instruído a abrir uma URL RTSP influenciável por atacante ficam expostos a essa vulnerabilidade
  • Pipelines de ingestão de mídia que buscam URLs de stream fornecidas por usuários entram no escopo de impacto
  • Sistemas de vigilância e CCTV que consomem feeds RTSP entram no escopo de impacto
  • Serviços de transcodificação que processam fontes remotas AV1-over-RTP entram no escopo de impacto
  • Não é necessário autenticação nem interação do usuário além de abrir o stream, e também não são necessárias flags incomuns de linha de comando
  • A vulnerabilidade é acionada durante a etapa normal de RTSP PLAY que esses clientes executam por design
  • O código PoC está em ffmpeg-dfvuln127

1 comentários

 
GN⁺ 3 시간 전
Comentários do Hacker News
  • O FFmpeg tem um histórico excepcionalmente ruim em termos de segurança
    Há muito tempo, praticamente toda vez que rodavam um fuzzer apareciam bugs de corrupção de memória quase sem fim, e também houve trabalho de funcionários do Google 10 anos atrás: https://security.googleblog.com/2014/01/ffmpeg-and-thousand-...
    Então, embora isso seja uma demonstração da capacidade de LLMs, não chega a ser surpreendente. Se você lida com conteúdo não confiável ou fornecido pelo usuário, não deveria executar o FFmpeg fora de um sandbox, e fazer isso é assumir um risco irracional

    • O pessoal do FFmpeg vem reclamando de forma consistente que há muita gente querendo divulgar vulnerabilidades do projeto, mas incomparavelmente menos pessoas dispostas a fazer o trabalho de patch para corrigi-las
    • Recentemente, desenvolvedores do FFmpeg participaram do podcast do Lex Fridman, e segurança também entrou na conversa
      Havia uma vulnerabilidade em um codec extremamente de nicho, usado talvez em um único videogame dos anos 90, e eles disseram algo na linha de que o denunciante tratou isso como se fosse um grande problema, mas que na prática não era nada demais por ser um codec quase nunca usado
      Mas fiquei pensando se eles não percebem que, se um atacante pode fornecer um arquivo de vídeo, ele pode escolher qualquer codec de vídeo que quiser. Mesmo que o desenvolvedor ache que esse codec nunca é usado, se ele ainda estiver disponível, o atacante pode usá-lo
      Fico curioso se deixei passar algo, se existe algum motivo válido para a vulnerabilidade desse codec realmente não ser grande coisa
    • Claro. Porque todo mundo conhece uma alternativa óbvia ao FFmpeg
    • Colocar o FFmpeg em sandbox por si só não é difícil, mas no caso de MPV/VLC e similares que usam FFmpeg a coisa fica mais complicada
      Até recentemente, nem sequer era possível colocar um player de vídeo em sandbox sem perder toda a aceleração por hardware, porque não existia contexto nativo de GPU virtio. Pelo menos não dava para impor isso de fora; internamente, ainda era possível isolar o FFmpeg como o Chromium faz e prendê-lo fortemente com seccomp
    • O FFmpeg opera em um domínio extremamente complexo e é um software muito complexo que precisa de foco extremo em desempenho
      Não é um problema só do FFmpeg. A Apple também teve incontáveis vulnerabilidades em decodificadores de imagem e vídeo. Essa área em si é muito difícil, e o FFmpeg faz mais coisas do que qualquer outro
  • Acho que a indústria está otimizando a coisa errada. É fácil usar algo como Mythos preview 1 ou GPT-5.5 para gerar milhares de relatórios de bugs escritos por IA. O difícil é corrigir os bugs de verdade
    Há alguns meses venho construindo um sistema que abre PRs em vez de só encontrar e reportar problemas críticos de segurança. Até agora, a taxa de aceitação é de cerca de 94%. A maior parte das falhas não veio de avaliação errada da vulnerabilidade, mas de kill switches específicos de projetos não documentados ou mecanismos internos
    Os desenvolvedores parecem gostar mais dessa abordagem. Relatórios de bug criam trabalho; bons PRs reduzem trabalho. Parece óbvio, mas muitos produtos de segurança ainda param no relatório e dão o caso por encerrado

    • A indústria na prática otimiza velocidade, time-to-market e funcionalidades, e aplica um modelo de avestruz a coisas que não geram receita no curto prazo, como considerações de segurança, acessibilidade, dependência de fornecedor e interoperabilidade
      Isso acontece desde que a indústria existe, e só agora estamos começando a ter ferramentas adequadas para avaliar o estrago e a fragilidade sistêmica resultante
    • Acho que tem algo faltando aqui. Software da Apple não tem código aberto, então não entendo como alguém proporia correções
  • Esse bug é sério pelo alcance que tem. Toda implantação em que o FFmpeg olha para uma URL RTSP influenciada por um atacante fica exposta
    Isso inclui pipelines de ingestão de mídia que consomem URLs de stream fornecidas pelo usuário, sistemas de vigilância e CFTV que puxam feeds RTSP, e serviços de transcodificação que processam fontes remotas de AV1-over-RTP. Na prática isso é bem sério, e o fato de ter sido divulgado é até surpreendente. Consigo pensar em vários serviços que parecem exploráveis agora mesmo

    • Também dá para argumentar que, se você conhece uma vulnerabilidade séria, divulgá-la é importante. Assim, quem usa o software de forma vulnerável pode tomar medidas para reduzir o risco
    • Para chegar à exploração real, ainda seria preciso algo adicional, como um vazamento de ASLR
    • O FFmpeg já deixou claro várias vezes que não liga para bugs ou relatórios de segurança
  • Mesmo que isso não seja tão grave quanto parece e soe como propaganda de empresa de segurança, serve para lembrar que há buracos de segurança em algum lugar de todo aplicativo que você lança, e que agora até script kiddies podem encontrá-los 5 minutos depois do lançamento com 2 dólares em créditos
    Se você não validar o código com red team antes do lançamento, os hackers farão isso por você depois

  • O termo zero-day está sendo usado de forma inflada. Nenhuma das vulnerabilidades descritas é de fato zero-day, mas chamar assim parece convincente e gera cliques

  • “Neste ponto, o ponteiro free corrompido é chamado e o controle do ponteiro de instrução é nosso” é algo muito sério
    Ainda assim, na prática, não parece que esse bug sozinho leve a execução remota arbitrária de código. Especialmente com ASLR, e ainda seria preciso existir em algum lugar uma página de memória gravável e executável

    • O texto passa rápido por essa parte, mas como a próxima variável da estrutura por acaso é o primeiro argumento da função, parece possível obter execução arbitrária de código com algo como system()
      Mesmo assim, para quebrar o ASLR seria necessário outro exploit
  • Isso não é o significado de “zero-day”

    • Parece que o termo perdeu o significado depois de se popularizar com a cobertura sobre o Stuxnet
    • Se vai dizer isso, seria bom explicar o significado também. Posso estar entendendo a definição errada
  • A estrutura de incentivos da área de pesquisa em segurança está profundamente quebrada
    Essas pessoas são como gerentes intermediários do mundo FOSS. Ganham elogios por empurrar mais trabalho para voluntários, e quanto mais urgente esse trabalho, mais elogios recebem. Reconhecer o impacto real ou as implicações práticas de um problema entra em conflito com os incentivos deles
    É difícil não vê-los como faxineiros do subsolo da indústria de software, e acho que já passou da hora de começar a tratá-los como párias. Que mandem um PR ou então fiquem quietos

  • Uso o FFmpeg há muito tempo, tanto pessoalmente quanto nos serviços que criei. Fabrice Bellard é um gênio, e os desenvolvedores que trouxeram o FFmpeg até aqui tornaram o mundo mensuravelmente mais rico
    Ainda assim, é difícil pensar em um programa que valha mais a pena colocar em sandbox do que o FFmpeg quando ele roda com entradas não confiáveis. Ele lida com codecs complexos de vídeo e áudio em uma enorme base de código em C, algo notoriamente difícil de tornar completamente correto
    Mesmo assim, na prática isso não é um problema tão grande. Rode o FFmpeg dentro de uma VM ou do gVisor, e o resultado final normalmente é um arquivo de vídeo que você estaria disposto a reproduzir no navegador. No navegador, ele também será decodificado dentro de outro sandbox, então isso já era algo difícil de qualquer forma

    • Tenho a previsão deprimente de que empresas detentoras de direitos autorais que querem DRM, “plataformas confiáveis” e captura regulatória vão ampliar parte do estrago aqui
      Um sandboxing seguro tende a virar uma oportunidade de permitir cópia irrestrita
    • Não entendi o que significa “um arquivo de vídeo que você estaria disposto a reproduzir no navegador”. Não seria seguro assumir que qualquer arquivo de vídeo não consegue escapar do sandbox de decodificação do navegador?
    • Mas a codificação muitas vezes também exige aceleradores de hardware, então no fim é comum ter de voltar a usar C
  • Trata-se de uma vulnerabilidade em que latm_parse_packet() faz uma soma com sinal de 32 bits no código de despacketização reversa de RTP LATM, sofre overflow e contorna a verificação de limites
    Mais uma vez surgiu uma vulnerabilidade por causa de uma soma sem checagem e, ainda assim, linguagens modernas como Rust ou Go não lançam exceção em overflow, e arquiteturas modernas de CPU como RISC-V também não oferecem trap de overflow. Linguagens antigas como C ou C++ também não têm verificação de overflow
    É ridículo. Está evidente que não dá para confiar que humanos escrevam código aritmético correto

    • Rust ativa a verificação de overflow no modo debug, e também dá para ativá-la no modo release. Na prática, isso é usado
      O comportamento padrão de overflow de inteiros no modo release do Rust também é definido; ele apenas faz wrapping. Isso reduz a chance de virar uma vulnerabilidade. Claro, isso muda quando você começa a usar unsafe Rust
    • Zig lança exceção em overflow. Para soma saturada e soma com wrapping, existem os operadores +|= e +%=
      Rust não gera exceção de overflow por padrão, mas dá para escrever algo como 123.checked_add(321). Aí o código fica mais difícil de ler, mas seguro contra overflow
      Sinceramente, pelo meu jeito de escrever código, eu preferiria algo como um comentário de fim de linha. Por exemplo, var x = y + z; # wrapped
      A chance de misturar aritmética com wrapping, checagem e saturação na mesma linha é muito baixa. No Zig, cada linha precisa poder ser compilada por si só, sem outro contexto de código, então um estado de compilador como doing(wrapped) { x + y } não pode existir. Nomes de função são verbosos demais, e conversões de tipo também são verbosas demais. Um modificador em nível de instrução pode ser um bom meio-termo