Compare funções perigosas com suas substitutas seguras. Buffer overflows são uma das principais vulnerabilidades de segurança há décadas.
#include <string.h> int main(void) { char buf[8]; // só 8 bytes strcpy(buf, "This is too long!"); // escreve 18 bytes → overflow return 0; }
sizeof ou uma constante).char dst[8]; strcpy(dst, src); // sem verificação de tamanho → overflow se src >= 8 bytes
char dst[8]; strncpy(dst, src, sizeof(dst) - 1); dst[sizeof(dst) - 1] = '\0'; // sempre termine explicitamente
'\0'. Você precisa adicioná-lo manualmente.char dst[8]; int n = snprintf(dst, sizeof(dst), "%s", src); // snprintf sempre termina em NUL (quando size > 0) // retorno n é "caracteres que tentaria escrever"; houve truncamento se n >= sizeof(dst) if (n >= (int)sizeof(dst)) { fprintf(stderr, "warning: truncated\n"); }
char buf[32]; sprintf(buf, "Hello, %s!", name); // name longo faz buf estourar
char buf[32]; snprintf(buf, sizeof(buf), "Hello, %s!", name);
int n = snprintf(buf, sizeof(buf), fmt, ...); if (n < 0) { /* erro de codificação */ } else if (n >= sizeof(buf)) { /* truncamento */ } else { /* OK: n bytes escritos */ }
gets não tem parâmetro de tamanho e foi removido no C11. Sempre use fgets.char line[64]; gets(line); // Errado: sem limite de tamanho
char line[64]; if (fgets(line, sizeof(line), stdin) == NULL) { // EOF ou erro }
char line[64]; if (fgets(line, sizeof(line), stdin)) { size_t len = strlen(line); if (len > 0 && line[len - 1] == '\n') { line[len - 1] = '\0'; } }
line[len-1] não será '\n'. Decida se vai fazer um loop para ler o resto ou reportar erro.atoi não consegue reportar erros e seu comportamento em overflow é indefinido. O strtol permite detectar corretamente "conversão falhou" e "fora de intervalo."int n = atoi(s); // s="abc" também retorna 0 → impossível diferenciar de um erro // s="99999999999" produz comportamento indefinido
#include <stdlib.h> #include <errno.h> errno = 0; char *end; long v = strtol(s, &end, 10); if (end == s) { /* nenhum dígito consumido */ } else if (*end != '\0') { /* lixo no final */ } else if (errno == ERANGE) { /* fora de intervalo */ } else { /* sucesso: valor é v */ }
#include <errno.h> #include <limits.h> #include <stdlib.h> int parse_int(const char *s, int *out) { errno = 0; char *end; long v = strtol(s, &end, 10); if (end == s || *end != '\0') return -1; if (errno == ERANGE || v < INT_MIN || v > INT_MAX) return -1; *out = (int)v; return 0; }
strtod para doubles e strtoul para unsigned long seguem o mesmo padrão.| Evite | Use no lugar | Observações |
|---|---|---|
strcpy | snprintf / strncpy+NUL | Nunca use. Sem verificação de tamanho |
strcat | strncat / snprintf | Mesmo problema do strcpy |
sprintf | snprintf | Detecta truncamento pelo valor de retorno |
gets | fgets | gets foi removido no C11 |
atoi / atof | strtol / strtod | Suporta detecção correta de erros |
scanf("%s", ...) | fgets + sscanf, ou uma largura como %31s | %s sem limite é inseguro |
gcc -Wall -Wextra -Wformat-security -Wstack-protector \
-fstack-protector-strong -D_FORTIFY_SOURCE=2 -O2 prog.c
-D_FORTIFY_SOURCE=2 adiciona verificações em tempo de execução via glibc, e -fstack-protector-strong aborta o programa em caso de corrupção de pilha.cppcheck, clang-tidy ou clang --analyze para pegar bugs de buffer antes de ir para produção.-fstack-protector-strong e observe a mensagem stack smashing detected.parse_int: escreva uma versão estrita que rejeita "123abc" e uma versão tolerante que aceita "3.14" e mantém a parte inteira. Adicione 10 casos de teste.char *read_line(FILE *fp, char *buf, size_t size);. Se a entrada exceder size, descarte o resto para que a próxima leitura comece limpa. Retorne buf, ou NULL em EOF.Confira seu entendimento desta aula.
strcpy?strcpy não verifica o tamanho do buffer, então é uma causa clássica de buffer overflows. Use variantes com limite de tamanho ou snprintf.
Escrever além da região alocada é comportamento indefinido e pode causar segfaults ou abrir portas para vulnerabilidades de execução de código arbitrário.
sprintf não aceita argumento de tamanho e é perigoso. snprintf recebe o tamanho do buffer, tornando-o seguro de usar.