11 pontos por GN⁺ 2026-01-01 | 5 comentários | Compartilhar no WhatsApp
  • O projeto cURL, depois de já ter removido strncpy(), agora também proibiu completamente strcpy() da base de código
  • strcpy() tem uma API simples, mas há o risco de a validação do tamanho do buffer ficar separada dela, o que a torna insegura na manutenção de longo prazo
  • Para substituí-la, foi introduzida uma nova função chamada curlx_strcopy(), que recebe tanto o tamanho do buffer de destino quanto o comprimento da string como argumentos e verifica se a cópia é possível antes de executá-la
  • A função usa memcpy() internamente e garante também o tratamento do caractere de terminação nula
  • Com essa mudança, é possível aumentar a segurança e a consistência do código, além de reduzir o problema de IAs gerarem relatórios incorretos de vulnerabilidade

Contexto da remoção de strcpy

  • No passado, o cURL já removeu todas as chamadas de strncpy(), apontando os problemas de API pouco intuitiva, falha em garantir terminação nula e preenchimento desnecessário com zeros dessa função
    • Nos casos em que era necessária a cópia de parte da string, a implementação foi alterada para usar memcpy() e tratar manualmente a terminação nula
  • strcpy() tem uma API simples, mas não explicita o tamanho do buffer, o que cria o risco de, durante a manutenção, o código de validação ficar separado da chamada de cópia
    • Quando o código é modificado ao longo de décadas por vários desenvolvedores, existe a possibilidade de a validação do tamanho do buffer ser neutralizada

Introdução de uma nova função de cópia de strings

  • Para evitar esse risco, foi introduzida uma função alternativa chamada curlx_strcopy()
    • Ela recebe como argumentos o buffer de destino, o tamanho do buffer, o buffer de origem e o comprimento da string de origem
    • A cópia com memcpy() só é realizada quando tanto a cópia quanto a terminação nula são possíveis
    • Em caso de falha, o buffer de destino é inicializado como string vazia
  • Essa função exige mais argumentos e mais código do que strcpy(), mas garante segurança ao acoplar de forma mais rígida a validação do buffer à operação de cópia
  • O uso de strcpy() foi completamente proibido na base de código do cURL, assim como já havia acontecido com strncpy()

Detalhes da implementação

  • Um exemplo da definição da função é o seguinte
    void curlx_strcopy(char *dest, size_t dsize, const char *src, size_t slen)
    {
      DEBUGASSERT(slen < dsize);
      if(slen < dsize) {
        memcpy(dest, src, slen);
        dest[slen] = 0;
      }
      else if(dsize)
        dest[0] = 0;
    }
    
  • Com DEBUGASSERT, é possível detectar erros mais cedo durante o desenvolvimento, e o código foi projetado para sempre ter sucesso em ambiente de produção
  • Assim como strcpy, ela não possui valor de retorno e adota uma abordagem de capturar erros nas etapas de teste e fuzzing

Reação da comunidade

  • Alguns desenvolvedores apontaram que ela se parece com strcpy_s() (C11 Annex K), mas o cURL ainda usa o padrão C89
  • Outras opiniões sugeriram a necessidade de adicionar um valor de retorno ou de melhorar a forma de tratamento quando o buffer falha
  • Em resposta, o cURL explicou que “como a função foi projetada para sempre ter sucesso, um valor de retorno é desnecessário”

Efeito colateral relacionado à IA

  • Com essa mudança, também é possível evitar o problema de chatbots de IA detectarem erroneamente o uso de strcpy no código do cURL e afirmarem que ele é vulnerável
  • Ainda assim, o autor observou que “a IA continua podendo gerar outros relatórios falsos”, mencionando assim as limitações da análise de código baseada em IA

5 comentários

 
ahwjdekf 2026-01-02

O certo é usar snprintf no lugar de strcpy. Se houver strcpy no código, tem que descobrir onde mora o desenvolvedor que fez aquilo.

 
winmain 2026-01-02

Esse era o jeito como eu trabalhava com código de depuração quando eu estava numa empresa de jogos há 25 anos, e não era só o strcpy, né. No release, isso voltava a ficar liberado para ganhar desempenho e assim era colocado em produção. Na verdade, no lado de jogos, colisão de memória é uma das coisas mais sensíveis, então o trabalho também era feito com muita cautela e atenção, a ponto de criarmos e usarmos nosso próprio depurador de memória. Mas hoje, olhando para trás, vejo que aquilo estava basicamente criando um garbage collector. Que lembrança nostálgica.

 
secwind 2026-01-02

Erro C4996 'strcpy': esta função ou variável pode não ser segura. Considere usar strcpy_s em vez disso. Para desativar a descontinuação, use _CRT_SECURE_NO_WARNINGS. Veja a ajuda online para mais detalhes.

 
GN⁺ 2026-01-01
Comentários do Hacker News
  • strcpy() não é ruim apenas do ponto de vista de segurança, mas também de desempenho
    Antigamente se pensava que strcpy() era eficiente quando o tamanho da string era desconhecido, mas na prática, por copiar um byte por vez, a CPU precisa fazer previsão de desvios, o que é ineficiente

    • Agora acho que deveríamos abandonar, sempre que possível, as próprias strings terminadas em nulo
    • Recentemente não vi strcpy usando laço escalar. Fico curioso se isso acontece só na arquitetura ARM
  • Sempre achei que as rotinas de string de C, sem exceção, têm grandes limitações, então acabam sendo pouco úteis
    Por isso, acho que faz falta uma biblioteca que registre, junto com o ponteiro da string, o tamanho da memória alocada
    Como exemplo, vale consultar a biblioteca bstring

    • strncpy surgiu para copiar nomes de arquivo de tamanho fixo. Para mais detalhes, veja esta resposta no StackOverflow
    • O motivo de não incluir informação de comprimento nas strings era economizar memória no passado. Na época, até um byte fazia falta
    • As funções de string de C causaram problemas porque foram adicionadas sem que os projetistas previssem plenamente as consequências. O fato de arrays serem forçados a virar ponteiros em argumentos de função também é um erro de projeto fundamental
    • Esse book-keeping adicional era um peso no passado, mas hoje está em um nível totalmente administrável
    • strncpy era originalmente uma função para lidar com campos de string de largura fixa. Por exemplo, servia para preencher com NUL um campo como char username[20]. Veja a documentação relacionada no manual string_copying.7
  • Acho estranho que curlx_strcopy não retorne indicação de sucesso ou falha
    Dá para verificar dest[0], mas isso tem alto potencial de gerar erro e não é intuitivo

    • A versão anterior retornava erro, mas agora falha silenciosamente e define uma string vazia. Isso é estranho
    • Provavelmente a ideia é considerar sucesso quando DEBUGASSERT(slen < dsize); passa, mas em builds release o assert pode ser removido. Acho melhor ter um código de erro explícito
    • Com esse tipo de projeto, acho bem possível aparecer um CVE no futuro
  • strncpy() originalmente não era para strings terminadas em nulo, mas para campos de tamanho fixo
    O problema começou quando analisadores estáticos passaram a recomendar strncpy no lugar de strcpy. As alternativas reais eram snprintf ou strlcpy

    • strlcpy é uma função da família BSD, então não faz parte do POSIX. A recomendação oficial é stpecpy, mas quase não há implementações reais. Veja a documentação relacionada
    • O motivo de strncpy preencher após o nulo era permitir comparações eficientes em campos de nomes de tamanho fixo, como entradas de diretório. Isso também está explicitado no documento de fundamentação do padrão ANSI C
  • Essa API parece algo no estilo do Annex-K. O tamanho do buffer de destino inclui espaço para o NUL, mas o tamanho da origem não inclui
    Acho que seria melhor simplesmente usar memcpy diretamente

  • No artigo, chamou atenção a frase de que “strcpy é uma isca para a IA gerar relatórios de vulnerabilidade incorretos

    • Na prática, a IA não apenas aponta strcpy como problema, mas cria provas complexas com erro lógico, fazendo os mantenedores perderem tempo verificando isso
    • Quem envia esses relatórios errados não sabe que a IA pode falhar, ou simplesmente não se importa. Afinal, não há custo por um relato incorreto
    • No fim, o problema são as pessoas usando IA para um uso inadequado
  • O princípio de “verifique perto do código” é bom, mas fica ambíguo quando é preciso verificar no início do ciclo de vida dos dados
    Acho que seria bom poder distinguir por tipo algo como “dado validado”, como acontece com o tipo Result em Rust

    • Result apenas representa sucesso/falha, e não garante um estado validado. Em vez disso, seria melhor ter um tipo separado que só possa ser criado após passar pelo processo de validação. Essa é a filosofia de “parse, don’t validate
    • O ideal é realizar a validação não perto do código consumidor, mas o mais cedo possível na fronteira do sistema. Mas para isso é preciso um sistema de tipos expressivo
    • Nesses casos, uma opção é separar os tipos como em String e CharSequence do Java
  • A diferença de off-by-one entre tamanho do buffer e comprimento da string é um problema de usabilidade terrível. Tem grande chance de continuar gerando erros

  • A nova função de cópia de string proposta esvazia o buffer de destino e retorna void quando a cópia não é possível
    Mas acho melhor tratar esse caso como erro e não mexer no buffer. Confiar apenas em DEBUGASSERT passa pouca segurança

  • Parabéns por concluir o projeto. Mesmo em C/C++, com esforço, dá para alcançar segurança de memória
    Só que, em ambiente móvel, o tamanho da fonte dos gráficos é pequeno demais, o que prejudica a legibilidade

    • Remover strcpy não torna o código automaticamente seguro em memória
    • A fonte dos gráficos parece ter sido projetada para impressão. Para blog, ela é pequena demais
 
hiongun 2026-01-04

Também é uma boa migrar de vez para a linguagem C3. Como é um projeto que mantém a sintaxe de C com mudanças mínimas e adiciona recursos modernos, a transição também é fácil.