2 pontos por GN⁺ 2025-09-24 | 2 comentários | Compartilhar no WhatsApp
  • A linguagem Go adicionou oficialmente suporte ao Valgrind
  • Essa mudança fortalece os recursos de detecção de erros de memória e depuração
  • Desenvolvedores passam a conseguir detectar com mais facilidade vazamentos de memória e erros de acesso
  • Com a melhoria de compatibilidade com o Valgrind, tarefas de portabilidade e manutenção podem ser realizadas com mais eficiência
  • Fica mais fácil avaliar a estabilidade do código Go em várias plataformas

A importância da introdução do suporte ao Valgrind no Go

  • Com a adição de suporte ao Valgrind no Go, desenvolvedores agora podem usar oficialmente essa ferramenta de detecção de erros de memória
  • Essa mudança permite identificar em código Go problemas como use-after-free, vazamentos de memória e acessos inválidos à memória
  • O Valgrind é amplamente usado para detectar problemas de memória em várias linguagens, e essa é uma mudança importante para reforçar a confiabilidade e robustez da comunidade Go
  • O recurso adicionado facilita várias tarefas em programas Go em diferentes plataformas, como depuração, validação de qualidade e avaliação de estabilidade
  • O principal significado desta atualização está no fato de que a camada de runtime do Go agora inclui código de instrumentação para o Valgrind

O que é o Valgrind?

  • Valgrind é uma ferramenta de desenvolvimento open source para verificar erros de memória, erros de thread, vazamentos de memória etc.
  • É amplamente usado em linguagens de programação de sistemas, como C e C++, e oferece detecção precisa de problemas de gerenciamento de memória

Resumo desta adição de funcionalidade

  • A instrumentação de código incluída nesta mudança permite que o Valgrind rastreie com precisão eventos relacionados à memória alocada dinamicamente no runtime do Go
  • Desenvolvedores poderão executar programas Go com o Valgrind para diagnosticar com eficiência problemas potenciais de memória ou acessos incorretos a ponteiros
  • Como resultado, há o benefício de manter código de alta qualidade e prevenir problemas com antecedência em infraestruturas ou serviços baseados em Go

Efeitos esperados da mudança

  • Espera-se que os processos de detecção de erros de memória e melhoria da qualidade do código em projetos Go se tornem mais precisos
  • Também se prevê que será mais fácil garantir a compatibilidade e confiabilidade do código Go distribuído em várias plataformas

2 comentários

 
taptaps 2025-09-25

Quando vejo posts sobre a linguagem Go, parece que sempre tem comentários do tipo
"mas com Rust isso não acontece", "com Rust nem precisa disso" kkk

 
GN⁺ 2025-09-24
Comentários do Hacker News
  • Sou o autor deste CL; com esta melhoria, quero tentar aproveitar o rastreamento de inicialização de memória para verificar se código criptográfico executa dentro de um tempo fixo (teste de tempo constante), de forma semelhante ao que o agl propôs há cerca de 15 anos e fez no BoringSSL link relacionado, porque essa propriedade é realmente muito difícil de testar; também espero vários outros efeitos interessantes, como explorar se, ao habilitar o uso de Valgrind no Go, será possível rastrear corretamente o tratamento de memória do runtime; dito isso, vale enfatizar que esse suporte ainda está em estágio experimental, não há 100% de certeza de que tudo funcione bem em todas as configurações, e podem surgir mais avisos difíceis de entender
    • Fico curioso se há alguma parte em que a comunidade possa ajudar no desenvolvimento
    • Acho um recurso realmente muito legal; espero que isso ajude a encontrar outros problemas no Go também; mas fico pensando se, em vez desse rastreamento complexo, não daria para simplesmente passar vários valores de entrada para a função criptográfica, medir diretamente o tempo de execução e, se todos forem iguais, verificar se há garantia de tempo constante; por exemplo, mesmo com Garbage Collection ou ruído do SO, talvez bastasse inserir vários inputs e, se as medições ficarem dentro de uma margem epsilon, já seria suficiente; além disso, alguns CPUs têm contador de desvios condicionais, e o depurador rr usa isso; talvez desse para comparar o número de desvios antes e depois da descriptografia com esse valor (relacionado à afirmação no texto do agl de que os desvios precisam ser iguais para haver tempo constante); e também seria possível pegar o maior tempo das 10 primeiras descriptografias, adicionar uma pequena folga e depois aplicar time padding em cada descriptografia seguinte (executando noop, por exemplo) para forçar os tempos a coincidirem; também dá para imaginar um assert que derrube o programa se passar do limite superior; mas o método fica difícil se o SO tirar o processo de execução e bagunçar o timing
  • Gostei muito do fato de que, em vez de adicionar os headers do Valgrind à árvore e usar cgo para chamar vários macros de requisição de cliente do Valgrind, optaram por disparar a requisição diretamente com uma única função em assembly emitindo a instrução necessária; esse tipo de abordagem é exatamente o desejável numa toolchain bootstrap, a ideia de criar apenas os blocos de construção mínimos e resolver todo o resto no nível da linguagem
    • Se esse caminho não tivesse sido escolhido e o método existente ou outras alternativas tivessem sido evitados, fico curioso sobre como seria possível fazer algo como o Go, mantendo o processo simples e com desempenho quase equivalente; acho que esse tipo de questão ainda vai precisar ser resolvido no futuro
  • É bom ver o rsc ainda contribuindo ativamente, especialmente deixando até comentários nas mensagens de commit; isso chama atenção; quanto mais velho fico, mais sinto a importância de mensagens de commit bem escritas; deixar só algo como "adiciona valgrind" não ajuda muito na hora de arquivar depois
    • O rsc é realmente um desenvolvedor nível rockstar; agora ele também está tentando coisas novas, como usar IA para lidar com issues e PRs, e espero que consiga bastante resultado
  • Esse recurso só é eficaz quando os testes são aplicados a todos os pacotes; caso contrário, ele acaba se perdendo no meio de avisos irrelevantes; por isso é difícil usar Valgrind com código Python
    • Se isso for verdade, então o mesmo deveria se aplicar a C e C++; no meu caso, usei Valgrind num programa híbrido Python + Boost C++, e depois de uma hora de trabalho num arquivo de suppressions consegui usar sem problemas
    • Um LLM local talvez fosse útil para organizar e resumir informação demais; por isso o papel de uma toolchain com baterias incluídas, como o Valgrind, é muito importante
    • Fico curioso sobre o que significa, no contexto do Go, "todos os pacotes são testados"
  • Valgrind é um superpoder escondido; na maior parte do software que escrevo, rodo os casos de teste com make check e depois executo os mesmos testes de novo com make check-valgrind dentro do ambiente do Valgrind; uso o segundo só no PC de desenvolvimento; assim acabo encontrando vazamentos de memória e bugs sutis com frequência
    • Concordo em parte, mas quando entra em multithreading (algo muito usado em Go), a camada de abstração do Valgrind não funciona tão bem; digo isso com base na última vez em que me aprofundei bastante em código C++, porque ele usa um escalonador próprio, então problemas de concorrência e race conditions do mundo real não aparecem tão bem no Valgrind; e, de modo geral, a perda de desempenho é bem severa; ainda assim, ele já me ajudou muito várias vezes, então sou grato por continuar existindo
  • Esse suporte é realmente muito legal; acho que vai expor mais alguns bugs; minha dúvida é por que escolheram Valgrind; imagino que Clang AddressSanitizer (asan) e MemorySanitizer (msan) encontrem erros mais variados (por exemplo, use-after-return) e sejam muito mais rápidos
    • Go não usa clang/llvm, então essas ferramentas não podem ser aplicadas
    • Go já tem suporte próprio a msan/asan há alguns anos
    • Valgrind é muito mais rápido, e também pode ser anexado a programas já em execução
    • Valgrind também tem várias funções, como rastreamento e profiling de memória, então é excelente também do ponto de vista de análise de desempenho
  • Muito impressionante; um dos maiores problemas no Go é profiling e os frequentes vazamentos/pressão de memória; no momento não conheço nenhuma ferramenta alternativa exata para resolver isso
    • Gostaria de ouvir mais detalhes; que problemas específicos de profiling você está enfrentando? Se o perfil de memória inuse não for suficiente para rastrear vazamentos de memória (fico curioso se usou gorefs), ajudaria saber que tipo de pressão de memória é o problema repositório goref; aliás, estamos trabalhando em continuous profiling na Datadog e contribuindo de forma constante para o profiling do runtime do Go
    • Fico curioso sobre como pode ocorrer um "vazamento de memória persistente" numa linguagem com GC
    • Idealmente, acho que deveria haver como controlar explicitamente o que vai para a stack, como em outras linguagens (em vez de depender só de escape analysis); no estado atual, é preciso ajustar coisas como a opção -gcflags -m=3 ou configurações do plugin Go do VSCode como ui.codelenses e ui.diagnostic.annotations, o que é incômodo
    • Sobre "vazamentos/pressão persistente de memória", no Go você não deve criar goroutines sem saber claramente como fazer a limpeza delas
    • O pprof também funciona bem até que ponto, então fico curioso sobre que funcionalidades você gostaria de ter a mais
  • Essa tentativa parece boa; há um risco se o mecanismo de requisição de cliente mudar, mas os headers quase não mudam (especialmente quando se adiciona uma nova plataforma), e o Go só lida com amd64 e arm64, então há menos chance de problema; a verdadeira vantagem desta melhoria não está tanto em evitar vazamentos de memória, mas em identificar com precisão memória não inicializada, porque, quando a memória é reutilizada sem passar por "poisoning" (marcação deliberada como proibida para uso), a análise fica difícil; esse recurso é bem útil também para as outras ferramentas, exceto cachegrind e callgrind
  • Essa melhoria parece menos um ganho e mais um pequeno fracasso para o ecossistema Go; gosto muito de Valgrind e usei bastante na época em que eu era desenvolvedor C; mas o fato de o Go precisar de Valgrind me dá a sensação de que ainda há algo insuficiente na linguagem ou no ecossistema; uso Rust há uns 6 anos e nunca senti necessidade de Valgrind nem uma vez (tirando uma vez em que um colega de equipe usou); sei que essa sensação provavelmente vem do cgo, mas ainda assim passa um ar de retrocesso
    • Não entendo por que os comentários mais votados sobre Go sempre incluem alguma cutucada envolvendo Rust; passa cada vez mais uma sensação defensiva e ao mesmo tempo de superioridade
    • O objetivo principal deste recurso não é tanto o rastreamento correto de memória, mas sim usá-lo para testar código de tempo constante, e ainda resta um pouco de explicação relacionada
    • Também já usei Valgrind muito de leve com Rust; não é algo muito necessário, mas a necessidade certamente existe; Rust é uma linguagem usada em ambientes muito diversos, desde código funcional de alto nível até código de microcontrolador bem ao estilo C; há lugares em que unsafe não é usado de forma alguma e outros em que é essencial; usar C via FFI também é algo comum, então eventualmente a necessidade aparece; no passado, quando criei um módulo Rust para o nginx (antes de existirem bindings oficiais/não oficiais), eu cometia erros com frequência e o valgrind me ajudou
    • A frequência de uso depende de quanto código unsafe você escreve, de quantos crates unsafe usa e de quantas bibliotecas C/C++ conecta; mesmo em Java, .NET e Node, isso pode acabar sendo necessário por causa de dependências externas