Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C strcpy() - evil?

Tags:

Some people seem to think that C's strcpy() function is bad or evil. While I admit that it's usually better to use strncpy() in order to avoid buffer overflows, the following (an implementation of the strdup() function for those not lucky enough to have it) safely uses strcpy() and should never overflow:

char *strdup(const char *s1) {   char *s2 = malloc(strlen(s1)+1);   if(s2 == NULL)   {     return NULL;   }   strcpy(s2, s1);   return s2; } 

*s2 is guaranteed to have enough space to store *s1, and using strcpy() saves us from having to store the strlen() result in another function to use later as the unnecessary (in this case) length parameter to strncpy(). Yet some people write this function with strncpy(), or even memcpy(), which both require a length parameter. I would like to know what people think about this. If you think strcpy() is safe in certain situations, say so. If you have a good reason not to use strcpy() in this situation, please give it - I'd like to know why it might be better to use strncpy() or memcpy() in situations like this. If you think strcpy() is okay, but not here, please explain.

Basically, I just want to know why some people use memcpy() when others use strcpy() and still others use plain strncpy(). Is there any logic to preferring one over the three (disregarding the buffer checks of the first two)?

like image 736
Chris Lutz Avatar asked Mar 04 '09 11:03

Chris Lutz


People also ask

Why is strcpy unsafe?

strcpy has no way of knowing how large the destination buffer is (i.e. there is no length parameter) so sloppy programming using it can lead to overrunning the buffer and corrupting other memory. Such an overrun can lead to crashes, odd behaviour and may be exploitable by malware authors.

Is strcpy safe in C?

Using strcpy() function to copy a large character array into a smaller one is dangerous, but if the string will fit, then it will not be worth the risk. If the destination string is not large enough to store the source string then the behavior of strcpy() is unspecified or undefined.

Why is strncpy not safe?

The strncpy() function is insecure because if the NULL character is not available in the first n characters in the source string then the destination string will not be NULL terminated. A program that demonstrates strncpy() in C++ is given as follows.

What can be used instead of strcpy?

If the length of the string you desire to copy is unknown, you can use snprintf here. This function sends formatted output to str. It acts similarily to sprintf() , but instead does not write more bytes allocated by str.


2 Answers

memcpy can be faster than strcpy and strncpy because it does not have to compare each copied byte with '\0', and because it already knows the length of the copied object. It can be implemented in a similar way with the Duff's device, or use assembler instructions that copy several bytes at a time, like movsw and movsd

like image 146
dmityugov Avatar answered Sep 22 '22 23:09

dmityugov


I'm following the rules in here. Let me quote from it

strncpy was initially introduced into the C library to deal with fixed-length name fields in structures such as directory entries. Such fields are not used in the same way as strings: the trailing null is unnecessary for a maximum-length field, and setting trailing bytes for shorter names to null assures efficient field-wise comparisons. strncpy is not by origin a ``bounded strcpy,'' and the Committee has preferred to recognize existing practice rather than alter the function to better suit it to such use.

For that reason, you will not get a trailing '\0' in a string if you hit the n not finding a '\0' from the source string so far. It's easy to misuse it (of course, if you know about that pitfall, you can avoid it). As the quote says, it wasn't designed as a bounded strcpy. And i would prefer not to use it if not necessary. In your case, clearly its use is not necessary and you proved it. Why then use it?

And generally speaking, programming code is also about reducing redundancy. If you know you have a string containing 'n' characters, why tell the copying function to copy maximal n characters? You do redundant checking. It's little about performance, but much more about consistent code. Readers will ask themselves what strcpy could do that could cross the n characters and which makes it necessary to limit the copying, just to read in manuals that this cannot happen in that case. And there the confusion start happen among readers of the code.

For the rational to use mem-, str- or strn-, i chose among them like in the above linked document:

mem- when i want to copy raw bytes, like bytes of a structure.

str- when copying a null terminated string - only when 100% no overflow could happen.

strn- when copying a null terminated string up to some length, filling the remaining bytes with zero. Probably not what i want in most cases. It's easy to forget the fact with the trailing zero-fill, but it's by design as the above quote explains. So, i would just code my own small loop that copies characters, adding a trailing '\0':

char * sstrcpy(char *dst, char const *src, size_t n) {     char *ret = dst;     while(n-- > 0) {         if((*dst++ = *src++) == '\0')             return ret;     }     *dst++ = '\0';     return ret; } 

Just a few lines that do exactly what i want. If i wanted "raw speed" i can still look out for a portable and optimized implementation that does exactly this bounded strcpy job. As always, profile first and then mess with it.

Later, C got functions for working with wide characters, called wcs- and wcsn- (for C99). I would use them likewise.

like image 35
Johannes Schaub - litb Avatar answered Sep 20 '22 23:09

Johannes Schaub - litb