What is the purpose of strlcpy and what was in the first version of its manual page?

2.5k Views Asked by At

By reading the man of strlcpy I met example:

Since it is known how many characters were copied the first time,
things can be sped 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().
As a matter of fact, the first version of this manual page got it wrong.

What is the whole purpose of strlcpy and how exactly the aforementioned example defeats it?

Also what was in the first version of this manual page and why it is still important to mention it in the new one?

2

There are 2 best solutions below

0
Eric Postpischil On BEST ANSWER

What is the purpose of strlcpy…?

Both strncpy and strlcpy guarantee not to attempt writing beyond length given by the third parameter, but they differ in how they handle the last character when the copy would go beyond the buffer:

  • strncpy copies a character from the source into the last byte of the destination.
  • strlcpy writes a null character into the last byte of the destination.

strncpy conceivably has uses such as completely filling a destination buffer and then, if the source was not completely copied, using realloc to allocate more memory for the destination and then completing the operation. However, it may be prone to misuse: Since it produces outputs that are not null-terminated, a programmer writing code using strings might inadvertently treat the destination as a null-terminated string, passing it to printf or other routines, resulting in a crash or other bugs.

strlcpy provides some safety from this sort of bug since its output is always a null-terminated string. (Of course, different types of bugs may occur, such as producing a string that is incorrect because an expected portion is missing or because it is shorter than expected.)

… and what was in the first version of it's manual page?

As the man page is making the point that replacing this code:

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

with this code:

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;

can improve efficiency but has a hazard of introducing bugs, we can presume the first version of the man page had a bug in the comparisons (n >= sizeof(pname) or strlcpy(…) >= sizeof(pname) - n) or the length and address calculations (pname + n, sizeof(pname) - n). Possibly > was used instead of >= or n-1 in place of n or some other off-by-one error. The specific error is inconsequential; the point is that more complicated code is more prone to human error.

0
John Bollinger On

What is the whole purpose of strlcpy and how exactly the aforementioned example defeats it?

That question mistakes the focus of the manual's remark, which is suggesting that strlcpy() should be used together with strlcat() in this case (eschewing the posited optimization), as presented in a previous example. The quoted example does not defeat the purpose of strlcpy(). It defeats the purpose of strlcpy() and strlcat(), as a pair.

When used together for this purpose, every call to either strlcpy() or strlcat() would be passed a pointer to the overall start of the destination buffer, and the full size of the buffer. This relieves the programmer of the need to track and use information about the current length of the destination string, which can be a source of errors. It is providing the ability to do this that the manual is referring to as the whole purpose of this pair of functions, though that's a bit of an exaggeration.

Also what was in the first version of this manual page and why it is still important to mention it in the new one?

The specifics are unclear, but the general point is that the original version of the page contained an error in that example, of exactly the kind that the recommended usage mode of strlcat() together with strlcpy() is intended to avoid. That is, an error in maintaining the length of the destination string or in using that appropriately.

But as to the first question actually posed, the primary purpose of strlcpy() as an individual function is to provide a variation on strncpy() that guarantees to NUL-terminate the destination string. This is a bit of a red herring, however, because strncpy() itself is one. The uninitiated are prone to mistake it for a safer strcpy(), but in fact, it is appropriate for only certain very special purposes. It is actually strncat() that is the safer strcpy():

#define safer_strcpy(dest, src, size) (*(dest) = '\0', strncat(dest, src, size))