size_t
strlcpy(char *dst, const char *src, size_t size)
size_t
strlcat(char *dst, const char *src, size_t size)
)
and
strlcat()
functions copy and concatenate strings respectively.
They are designed
to be safer, more consistent, and less error prone replacements for
strncpy(3)
and
strncat(3).
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 is at least one byte free in
dst).
Note that you should include a byte for the NUL in
size.
Also note that
strlcpy()
and
strlcat()
only operate 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
size
- strlen(dst) - 1 bytes, NUL-terminating the result.
)
and
strlcat()
functions return the total length of the string they tried to create.
For
strlcpy()
that means the length of
src.
For
strlcat()
that means the initial length of
dst
plus
the length of
src.
While this may seem somewhat confusing it was done to make
truncation detection simple.
Note however, that if
strlcat()
traverses
size
characters without finding a NUL, the length of the string is considered
to be
size
and the destination string will not be NUL-terminated (since there was
no space for the NUL).
This keeps
strlcat()
from running off the end of a string.
In practice this should not happen (as it means that either
size
is incorrect or that
dst
is not a proper
``C''
string).
The check exists to prevent potential security problems in incorrect code.
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, something like the following might be used:
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().
)
and
strlcat()
first appeared in
OpenBSD2.4,
then in
NetBSD1.4.3
and
FreeBSD3.3.