Em todos os cenários de cópia / movimentação de string - strcat (), strncat (), strcpy (), strncpy (), etc. - as coisas vão muito melhor ( mais seguras ) se algumas heurísticas simples forem aplicadas:
1. Sempre preencher NUL seu (s) buffer (es) antes de adicionar dados.
2. Declare buffers de caracteres como [SIZE + 1], com uma constante de macro.
Por exemplo, dado:
#define BUFSIZE 10
char Buffer[BUFSIZE+1] = { 0x00 }; /* The compiler NUL-fills the rest */
podemos usar códigos como:
memset(Buffer,0x00,sizeof(Buffer));
strncpy(Buffer,BUFSIZE,"12345678901234567890");
com relativa segurança. O memset () deve aparecer antes de strncpy (), mesmo que tenhamos inicializado o Buffer em tempo de compilação, porque não sabemos que lixo o outro código colocou nele antes de nossa função ser chamada. O strncpy () truncará os dados copiados para "1234567890" e não os encerrará em NUL. No entanto, uma vez que já preenchemos o NUL de todo o buffer - sizeof (Buffer), em vez de BUFSIZE - é garantido que haverá um final "fora do escopo" finalizando o NUL de qualquer maneira, contanto que restrinjam nossas gravações usando o BUFSIZE constante, em vez de sizeof (Buffer).
Buffer e BUFSIZE também funcionam bem para snprintf ():
memset(Buffer,0x00,sizeof(Buffer));
if(snprintf(Buffer,BUFIZE,"Data: %s","Too much data") > BUFSIZE) {
/* Do some error-handling */
} /* If using MFC, you need if(... < 0), instead */
Embora snprintf () grave especificamente apenas caracteres BUFIZE-1, seguidos de NUL, isso funciona com segurança. Portanto, "desperdiçamos" um byte NUL estranho no final do Buffer ... evitamos o estouro do buffer e as condições de string não terminadas, por um custo de memória bem pequeno.
Minha chamada em strcat () e strncat () é mais rígida: não os use. É difícil usar strcat () com segurança, e a API para strncat () é tão contra-intuitiva que o esforço necessário para usá-la corretamente anula qualquer benefício. Proponho a seguinte visita:
#define strncat(target,source,bufsize) snprintf(target,source,"%s%s",target,source)
É tentador criar um drop-in strcat (), mas não é uma boa ideia:
#define strcat(target,source) snprintf(target,sizeof(target),"%s%s",target,source)
porque target pode ser um ponteiro (portanto, sizeof () não retorna as informações de que precisamos). Não tenho uma boa solução "universal" para instâncias de strcat () em seu código.
Um problema que encontro frequentemente com programadores "cientes de strFunc ()" é uma tentativa de proteção contra estouros de buffer usando strlen (). Isso é bom se o conteúdo tiver a garantia de terminação NUL. Caso contrário, strlen () em si pode causar um erro de saturação de buffer (geralmente levando a uma violação de segmentação ou outra situação de despejo de núcleo), antes mesmo de você alcançar o código "problemático" que está tentando proteger.