Thread: "The Insidious strncpy - Just an FYI"

  1. #1
    Registered User penney's Avatar
    Join Date
    Jan 2003
    Posts
    47

    "The Insidious strncpy - Just an FYI"

    The purpose of the strncpy is supposedly to perform safe copies so as to not exceed the limits of your string sizes. The problem with the strncpy is that if your source string is longer than your destination string, then the strncpy will NOT NULL terminate the destination string even though you may have been prudent in limiting the number of characters read from the source string to the total size of the destination string minus 1. This means that you must always ensure that your final destination strings are always NULL terminated prior to or just after using the strncpy function. For example: Let’s assume you have defined -> char str[5]; and you issued the command: strncpy(str,”my string”,4); You would have an non terminated str string with “my s” as the first 4 characters. You would have to perform a str[5]=’\0’; or some variation thereof to null terminate the string.

  2. #2
    The larch
    Join Date
    May 2006
    Posts
    3,573
    IMO, you probably just have a problem if the target string is too short, unless you are happy with getting a truncated string.

    For this reason, I don't quite understand how strncpy can be considered a safe strcpy, since data integrity might be just as important as mechanically avoiding buffer overflows. In the general case, I make sure that I allocated enough memory for the target string and use strcpy, and reserve strncpy for other things than just making a plain copy of some string. (strncpy rather seems to me as providing substring extraction)
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  3. #3
    Jack of many languages Dino's Avatar
    Join Date
    Nov 2007
    Location
    Chappell Hill, Texas
    Posts
    2,332
    If you perform a str[5] = '\0' on a char str[5], you've become the storage corruptor yourself.
    Mainframe assembler programmer by trade. C coder when I can.

  4. #4
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >The purpose of the strncpy is supposedly to perform safe
    >copies so as to not exceed the limits of your string sizes.

    This is a common myth, and it's the key instigator in creating the very class of bugs you warn against in your post. In reality, strncpy was designed with fixed length fields in mind. For that purpose strncpy is well suited, and only when you try to use it as a "safe" strcpy does it start to become a wart. I see this as akin to not understanding that scanf was designed for strictly formatted input (not user input), then complaining that scanf has "problems". In other words, PEBKAC.

    I strongly recommend that you use strncpy for what it was designed rather than as an ill suited band-aid to a problem that really stems from undisciplined use of strcpy. If you turn on your brain, strcpy can be used safely. If you don't believe that or don't trust yourself to do it well, there are many third party alternatives such as strlcpy that do what most people think strncpy does.
    My best code is written with the delete key.

  5. #5
    Registered User
    Join Date
    Apr 2006
    Posts
    58
    If you are really paranoid about such stuff, you can try snprintf. But calling snprintf is probably more expensive than calling the string copy functions.

    Code:
    int snprintf(char *restrict s, size_t n, const char *restrict format, ...);
    The snprintf() function shall be equivalent to sprintf(), with the addition of the n argument which states the size of the buffer referred to by s.
    If n is zero, nothing shall be written and s may be a null pointer. Other-wise, output bytes beyond the n-1st shall be discarded instead of being written to the array, and a null byte is written at the end of the bytes actually written into the array.


    But in any case the man page does say "it is the user's responsibility to ensure that enough space is available."

  6. #6
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by Prelude View Post
    In other words, PEBKAC.
    Haven't heard that one in a while.

  7. #7
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    As mentioned, one should not just code using functions, which do ease work and code a bit, without knowing all the ramifications that go with using that function call. This function does do what it is intended to do, you just have to be smart about using it. You should not trust any function within a library unless you have created it yourself and know what its purpose and limits are. This goes for any programming language, really, and not just for c.

  8. #8
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by slingerland3g View Post
    As mentioned, one should not just code using functions, which do ease work and code a bit, without knowing all the ramifications that go with using that function call.
    True, but it also falls on the function's designer to provide an interface which is not confusing and error-prone. But strncpy() isn't the only function I could complain about.

    You know what drives me crazy? The fact that the FILE * parameter to fwrite() is the last parameter in the list, while the FILE * parameter to fputc() is the first parameter in the list.

    Programming in C for 17 years and I still need to look it up. Every. Single. Time.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  9. #9
    Registered User
    Join Date
    Sep 2006
    Posts
    8,868
    fputc() comes *FIRST*
    fwrite() comes *LAST*

    in the list of the two functions. OK, it's thin, but it's something to help remember it.

  10. #10
    Registered User slingerland3g's Avatar
    Join Date
    Jan 2008
    Location
    Seattle
    Posts
    603
    Quote Originally Posted by brewbuck View Post
    True, but it also falls on the function's designer to provide an interface which is not confusing and error-prone. But strncpy() isn't the only function I could complain about.

    You know what drives me crazy? The fact that the FILE * parameter to fwrite() is the last parameter in the list, while the FILE * parameter to fputc() is the first parameter in the list.

    Programming in C for 17 years and I still need to look it up. Every. Single. Time.

    Yes, very true. I still have issues in trying to understand the API for writing to the kernel to test the arp and or routing table limits for debugging.

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by brewbuck View Post
    True, but it also falls on the function's designer to provide an interface which is not confusing and error-prone. But strncpy() isn't the only function I could complain about.

    You know what drives me crazy? The fact that the FILE * parameter to fwrite() is the last parameter in the list, while the FILE * parameter to fputc() is the first parameter in the list.

    Programming in C for 17 years and I still need to look it up. Every. Single. Time.
    Heheh. So true.

    Another one that's always gotten on my nerves is fgets - I can't think of a single case where I actually needed the newline (if it's even present; which means that if you really do need one you'll have to check anyway).
    Last edited by Sebastiani; 11-06-2009 at 02:19 PM.

  12. #12
    Code Goddess Prelude's Avatar
    Join Date
    Sep 2001
    Posts
    9,897
    >fgets - I can't think of a single case where I actually needed the newline
    Actually, I've found myself using the newline for its intended purpose many a time. If the newline is present, the line is complete. If not present, fgets read a partial line and the application needs to do more work to avoid losing data or corrupting the flow of input. This is important information, considering that we're forced to use a fixed sized buffer with fgets in all cases.
    My best code is written with the delete key.

  13. #13
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    Quote Originally Posted by Prelude View Post
    >fgets - I can't think of a single case where I actually needed the newline
    Actually, I've found myself using the newline for its intended purpose many a time. If the newline is present, the line is complete. If not present, fgets read a partial line and the application needs to do more work to avoid losing data or corrupting the flow of input. This is important information, considering that we're forced to use a fixed sized buffer with fgets in all cases.
    That's one possibility. Another possibility is that it's the last line of the file, and it happened to not have a trailing newline. To tell the difference, you have to try to get a character to check if it's EOF. If not, you need to unget it. Gross.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  14. #14
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    Quote Originally Posted by Prelude View Post
    >fgets - I can't think of a single case where I actually needed the newline
    Actually, I've found myself using the newline for its intended purpose many a time. If the newline is present, the line is complete. If not present, fgets read a partial line and the application needs to do more work to avoid losing data or corrupting the flow of input. This is important information, considering that we're forced to use a fixed sized buffer with fgets in all cases.
    Ah, that makes sense. Which explains why 'gets' discards it instead (no buffer limit).

    Quote Originally Posted by Brewbuck
    That's one possibility. Another possibility is that it's the last line of the file, and it happened to not have a trailing newline. To tell the difference, you have to try to get a character to check if it's EOF. If not, you need to unget it. Gross.
    In that case though you could always use 'feof'. I always follow it up by an 'ferror' anyway to handle the however-rare-but-possible hard-disk failure (or maybe not so rare, considering the technologies in use today (usb, etc)).

  15. #15
    Lurking whiteflags's Avatar
    Join Date
    Apr 2006
    Location
    United States
    Posts
    9,612
    > In that case though you could always use 'feof'.

    I don't see how that would be different than what brewbruck suggested. If you grabbed the last line of some file, you can't just check feof(), you have to read again to enter eof state. TBH, feof() would report a wrong result about as often as a hard-disk failure occurs anyway, since you would have to read exactly the amount of characters left in order to avoid eof state, but apples and oranges are possible.
    Last edited by whiteflags; 11-07-2009 at 03:44 AM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. strcpy and strncpy
    By roaan in forum C Programming
    Replies: 5
    Last Post: 07-26-2009, 08:04 PM
  2. why is strncpy segfaulting here?
    By Calef13 in forum C Programming
    Replies: 3
    Last Post: 12-29-2008, 03:27 PM
  3. strncpy adavnced :P
    By Joke in forum C Programming
    Replies: 3
    Last Post: 07-14-2008, 11:14 AM
  4. strncpy question, size -1??
    By fayte in forum C Programming
    Replies: 16
    Last Post: 03-16-2006, 11:32 PM
  5. strncpy doesn't seem to work
    By linucksrox in forum C++ Programming
    Replies: 3
    Last Post: 09-08-2005, 01:34 PM