A rant about strcpy, strncpy and strlcpy.


Here's a little rant about strcpy, strncpy and strlcpy.  

(You'll note that I cite a variety of sources including Microsoft,
Unix and Apple documentation, so this is a very ecumenical
discussion. :-) )

I teach that strcpy is dangerous, and should avoided in favor
of strncpy.

The following article from the Microsoft Developer's Network (MSDN) is very
harshly critical of this teaching, so I recommend this article to
you for your
consideration and critical analysis.

 link to MSDN article mentioning strcpy vs strncpy

Funny, I think the MSDN author's line of argument actually just
supports my point rather than refutes it, since strcpy is an example
of the kind of code he claims should not be written (a loop bounded by
reaching a \0 rather than by a counter.)

Of course, the cure (strncpy) can be as bad as the disease; maybe that's
the MSDN author's point.  I appreciate his point that strcpy can be
used safely in LIMITED circumstances, and strncpy can be unsafe if you
aren't careful.

For example, a key problem with strncpy is that if the length of the
src string is >= n, you end up without null termination.  I usually
do the following for safety:

char dest[LEN];
char *src;

 ... /* src is set to point to a source string of unknown length */

strncpy(dest,src,LEN);
dest[LEN-1]='\0'; /* null terminate for safety */

Maybe code without that extra null termination is an example
of code that uses strncpy but is nevertheless dangerous.

The assignment of dest[LEN-1] to \0 is redundant and harmless 
if the string is already NULL terminated, and vital if strlen(src) >= LEN.

I'm assuming that a one byte copy is cheap enought that it isn't worth
the cycles or the code clutter to do an if test to check whether the
assignment is strictly necessary (e.g. if strlen(src) >= LEN).

In each lecture where I've taught this, one of the more clever students
has asked (both in 105 and 181) something to the effect of "why doesn't
strncpy just do that NULL terminating thing for you"?   

I've replied: "Are you suggesting, in so many words, that strncpy's
behavior is kind of dumb?" They say, "yeah".  I say "Well, I agree
with you, and apparently someone else did too, because someone came
along and wrote a function called strlcpy, that does something more
like what we might expect strncpy to do.  See:

        "man strlcpy" on strauss

        http://www.daemon-systems.org/man/strlcpy.3.html


But since strlcpy came along later, it is not as widely-implemented
or widely known.  Lots of textbooks don't talk about it, and some systems
don't implement it yet.  So you need to know about strncpy.

Note, for example, what the Apple documentation for strcpy/strncpy says about
strlcpy; namely, that it is "not defined in any standards" and "should only be
used when portability is not a concern."

     link to strcpy page in Apple developer docs

The Apple page for strlcpy
also has some interesting information on the topic:

     link to strlcpy page in Apple developer docs


Here's a question for reflection.  My proposed way of copying a string is:


 char dest[LEN];
 char *src;
 
 ... /* src is set to point to a source string of unknown length */

 strncpy(dest,src,LEN);
 dest[LEN-1]='\0'; /* null terminate for safety */


Sometimes a student will suggest "why not just copy one fewer characters; 
doesn't that fix things so that you don't need the extra line to do
the NULL terminating?"

For example:

 char dest[LEN];
 char *src;

 ... /* src is set to point to a source string of unknown length */

 strncpy(dest,src,LEN-1);

My reply is that this doesn't work.   Can you explain why it doesn't?
Under what circumstances does this fail to result in a null-terminated
destination string?

Final Thoughts


Phillip T Conrad
Last modified: Tue Nov 30 14:56:06 EST 2004