My version of strlcpy

gcc 4.4.4 c89

My program performs many copy operations. I do not want to use strncpy since it does not terminate nul. And I cannot use strlcpy as it is not portable.

A few questions. How can I put my function through my steps to make sure that it is completely safe and stable. Unit testing?

How much is enough for production?

size_t s_strlcpy(char *dest, const char *src, const size_t len) { size_t i = 0; /* Always copy 1 less then the destination to make room for the nul */ for(i = 0; i < len - 1; i++) { /* only copy up to the first nul is reached */ if(*src != '\0') { *dest++ = *src++; } else { break; } } /* nul terminate the string */ *dest = '\0'; /* Return the number of bytes copied */ return i; } 

Thanks so much for any suggestions,

+4
source share
9 answers

Although you can just use another strlcpy function, as another message recommends, or use snprintf(dest, len, "%s", src) (which always completes the buffer), this is what I noticed when looking at your code:

 size_t s_strlcpy(char *dest, const char *src, const size_t len) { size_t i = 0; 

It is not necessary to create len const here, but it can be useful as it checks that you are not modifying it.

  /* Always copy 1 less then the destination to make room for the nul */ for(i = 0; i < len - 1; i++) { 

Unfortunately. What if len 0? size_t usually unsigned, so (size_t) 0 - 1 will become something like 4294967295 , causing your routine to move through your program memory and break into an unprinted page.

  /* only copy up to the first nul is reached */ if(*src != '\0') { *dest++ = *src++; } else { break; } } /* nul terminate the string */ *dest = '\0'; 

The above code looks good to me.

  /* Return the number of bytes copied */ return i; } 

According to Wikipedia , strlcpy returns strlen(src) (actual string length), and not the number of bytes copied. Therefore, you need to continue counting characters in src until you hit '\0' , even if it exceeds len .

Also, if your for loop ends in len - 1 , your function will return len-1 , not len, as you expected.


When I write such functions, I usually prefer to use the start pointer (call it S) and the end pointer (call it E). S indicates the first character, and E indicates one character after the last character (which makes it such that E - S is the length of the string). Although this technique may seem ugly and obscure, I found it pretty reliable.

Here is the above version of how I will write strlcpy:

 size_t s_strlcpy(char *dest, const char *src, size_t len) { char *d = dest; char *e = dest + len; /* end of destination buffer */ const char *s = src; /* Insert characters into the destination buffer until we reach the end of the source string or the end of the destination buffer, whichever comes first. */ while (*s != '\0' && d < e) *d++ = *s++; /* Terminate the destination buffer, being wary of the fact that len might be zero. */ if (d < e) // If the destination buffer still has room. *d = 0; else if (len > 0) // We ran out of room, so zero out the last char // (if the destination buffer has any items at all). d[-1] = 0; /* Advance to the end of the source string. */ while (*s != '\0') s++; /* Return the number of characters between *src and *s, including *src but not including *s . This is the length of the source string. */ return s - src; } 
+11
source

IMHO, just buy the original strlcpy , as Ignacio Vasquez-Abram says. OpenBSDs code is hacked and the license terms are rock;).

As for your code, I would add to what others have already said, this is just a matter of personal taste:

 /* only copy up to the first nul is reached */ if(*src != '\0') { *dest++ = *src++; } else { break; } 

I would write it like this:

 if(*src == '\0') { break; } *dest++ = *src++; 

Itโ€™s because it reduces the amount of unnecessary code that people should read, but because my "style" writes this path sequentially, and not if (ok) { do } else { handle error } . The comment above if is also redundant (see the comment above the for loop).

+4
source

Why don't you use something like memccpy () instead of skating yourself? You just need to complete with a zero byte, but it is simpler and usually faster to increase the standard function than starting from scratch.

Some architectures will greatly optimize or even use the assembly for string functions in order to squeeze good performance out of them.

Without creating or debugging:

 str = memccpy (dest, src, '\0', len); if(str) *str = '\0'; 
+3
source

I would suggest that White-box testing is useful for such a function (a unit testing form).

+2
source

There is the principle of DRY "do not repeat yourself." In other words, do not create new code to execute what has already been done. Check out the standard C library, as shown in the example above (WhilrWind).

One reason is the testing mentioned. The standard C library has been tested for many years, so this is a safe bet that it works as advertised.

Learning while playing with code is a great idea, keep trying.

+2
source

Yes, unit testing. Check with lots of randomly generated rows.

Looks good to me.

+1
source

I think it is a mistake to rely on length and do arithmetic.

The size_t type is unsigned. Think about how your function will work if it is called with a null purpose.

+1
source

Unit testing? How much is enough for production?

Probably for a โ€œsimpleโ€ function such as this may be enough, although the only real way to test the function is to try to break it.

Navigate to it with NULL pointers, long strings 10,000 long, negative len values, invalid data, etc. In general, think: if you were a malicious user trying to break it, how would you do it?

See link in answer here

+1
source

Source: https://habr.com/ru/post/1311272/


All Articles