home texts sources

Safe C programming

Author: Yegor Samusev <yegor@samusev.pp.ru>
Modified:2010-12-08

The main problem in C programming is buffer overflow. To avoid it you must use correctly safe C functions instead unsafe ones. Unsafe functions exist only for compatibility with old sources.

Contents

stdio.h

fgets()

Don't use gets()!

char *
fgets(char * restrict str, int size, FILE * restrict stream);

The right usage:

fgets(str, sizeof (str), stdin);

Example:

char str[10];
printf("Name [%d]? ", sizeof (str));
fgets(str, sizeof (str), stdin);
printf("Hello, %s!\n", str);

snprintf()

Don't use sprintf()!

int
snprintf(char * restrict str, size_t size, const char * restrict format, ...);

The right usage:

snprintf(str, sizeof (str), format, ...);

Example:

char str[5];
char *format = "%02x%02x%02x";
snprintf(str, sizeof (str), format, 'B', 'S', 'D'); /* "4253\0" */

string.h

Use strncat() rather than strcat() and strncpy() rather than strcpy() but in BSD, Mac OS X, Solaris and IRIX you must use strlcat() and strlcpy() instead strncat() and strncpy() because they are more safe.

strncat()

char *
strncat(char * restrict s, const char * restrict append, size_t count);

The right usage:

strncat(s, append, sizeof (s) - strlen(s) - 1);

Example:

char s[] = {'F', 'r', 'e', 'e', '\0', '*', '*'};
char *append = "BSD";
strncat(s, append, sizeof (s) - strlen(s) - 1); /* "FreeBS\0" */

strlcat()

size_t
strlcat(char *dst, const char *src, size_t size);

The right usage:

strlcat(dst, src, sizeof (dst));

Example:

char dst[] = {'F', 'r', 'e', 'e', '\0', '*', '*'};
char *src = "BSD";
strlcat(dst, src, sizeof (dst)); /* "FreeBS\0" */

strncpy()

char *
strncpy(char * restrict dst, const char * restrict src, size_t len);

The right usage:

strncpy(dst, src, sizeof (dst) - 1);
dst[sizeof (dst) - 1] = '\0';

Example:

char dst[] = {'*', '*', '*', '*', '*'};
char *src = "HELLO";
strncpy(dst, src, sizeof (dst) - 1); /* "HELL*" */
dst[sizeof (dst) - 1] = '\0';        /* "HELL\0" */

strlcpy()

size_t
strlcpy(char *dst, const char *src, size_t size);

The right usage:

strlcpy(dst, src, sizeof (dst));

Example:

char dst[] = {'*', '*', '*', '*', '*'};
char *src = "HELLO";
strlcpy(dst, src, sizeof (dst)); /* "HELL\0" */

Test for strncpy() and strlcpy()

The dst is:

char dst[5];

The dot symbol shows where data is unchanged.

Function src dst Comment
strncpy(dst, src, sizeof (dst)) HELLO\0 HELLO Unsafe.
strlcpy(dst, src, sizeof (dst)) HELLO\0 HELL\0 Safe!
strncpy(dst, src, 1) HELLO\0 H.... Unsafe but fast.
strlcpy(dst, src, 1) HELLO\0 \0.... Safe!
strncpy(dst, src, sizeof (dst)) X\0 X\0\0\0\0 Safe but slow.
strlcpy(dst, src, sizeof (dst)) X\0 X\0... Safe and fast!