strlcat(), strlcpy()

Size-bounded string copying and concatenation

Synopsis:

#include <string.h>

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

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

Arguments:

dst
A pointer to the destination string.
src
A pointer to the source string.
size
The size of the destination buffer.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The strlcpy() and strlcat() functions copy and concatenate strings respectively. They're designed to be safer, more consistent, and less error-prone replacements for strncpy() and strncat().

Unlike those functions, strlcpy() and strlcat() take the full size of the buffer (not just the length) and guarantee to NUL-terminate the result (as long as size is larger than 0 or, in the case of strlcat(), as long as there's at least one byte free in dst).


Note: You should include a byte for the NUL in size. Also note that strlcpy() and strlcat() operate only on true “C” strings. This means that for strlcpy(), src must be NUL-terminated, and for strlcat(), both src and dst must be NUL-terminated.

The strlcpy() function copies up to size − 1 characters from the NUL-terminated string src to dst, NUL-terminating the result.

The strlcat() function appends the NUL-terminated string src to the end of dst. It will append at most sizestrlen(dst) − 1 bytes, NUL-terminating the result.

Returns:

The total length of the string:


Note: If strlcat() traverses size characters without finding a NUL, the length of the string is considered to be size, and the destination string isn't NUL-terminated (since there was no space for the NUL). This keeps strlcat() from running off the end of a string. In practice this shouldn't happen (as it means that either size is incorrect or that dst isn't a proper “C” string). The check exists to prevent potential security problems in incorrect code.

Examples:

The following code fragment illustrates the simple case:

char *s, *p, buf[BUFSIZ];

...

(void)strlcpy(buf, s, sizeof(buf));
(void)strlcat(buf, p, sizeof(buf));

To detect truncation, perhaps while building a pathname, you could use something like this:

char *dir, *file, pname[MAXPATHLEN];

...

if (strlcpy(pname, dir, sizeof(pname)) >= sizeof(pname))
        goto toolong;
if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
        goto toolong;

Since we know how many characters we copied the first time, we can speed things up a bit by using a copy instead of an append:

char *dir, *file, pname[MAXPATHLEN];
size_t n;

...

n = strlcpy(pname, dir, sizeof(pname));
if (n >= sizeof(pname))
        goto toolong;
if (strlcpy(pname + n, file, sizeof(pname) - n) >=
            sizeof(pname) - n)
        goto toolong;

However, one may question the validity of such optimizations, as they defeat the whole purpose of strlcpy() and strlcat().

Classification:

Unix

Safety:
Cancellation point No
Interrupt handler Yes
Signal handler Yes
Thread Yes

Contributing author:

OpenBSD

See also:

snprintf(), strncpy(), strncat()