strncpy or strlcpy in my case

35,013

Solution 1

strncpy is never the right answer when your destination string is zero-terminated. strncpy is a function intended to be used with non-terminated fixed-width strings. More precisely, its purpose is to convert a zero-terminated string to a non-terminated fixed-width string (by copying). In other words, strncpy is not meaningfully applicable here.

The real choice you have here is between strlcpy and plain strcpy.

When you want to perform "safe" (i.e. potentially truncated) copying to dst_arr, the proper function to use is strlcpy.

As for dst_ptr... There's no such thing as "copy to dst_ptr". You can copy to memory pointed by dst_ptr, but first you have to make sure it points somewhere and allocate that memory. There are many different ways to do it.

For example, you can just make dst_ptr to point to dst_arr, in which case the answer is the same as in the previous case - strlcpy.

Or you can allocate the memory using malloc. If the amount of memory you allocated is guaranteed to be enough for the string (i.e. at least strlen(src_str) + 1 bytes is allocated), then you can use the plain strcpy or even memcpy to copy the string. There's no need and no reason to use strlcpy in this case , although some people might prefer using it, since it somehow gives them the feeling of extra safety.

If you intentionally allocate less memory (i.e. you want your string to get truncated), then strlcpy becomes the right function to use.

Solution 2

strlcpy() is safer than strncpy() so you might as well use it.
Systems that don't have it will often have a s_strncpy() that does the same thing.

Note : you can't copy anything to dst_ptr until it points to something

Solution 3

I did not know of strlcpy. I just found here that:

The strlcpy() and strlcat() functions copy and concatenate strings respectively. They are designed to be safer, more consistent, and less error prone replacements for strncpy(3) and strncat(3).

So strlcpy seams safer.

Edit: A full discussion is available here.

Edit2:

I realize that what I wrote above does not answer the "in your case" part of your question. If you understand the limitations of strncpy, I guess you can use it and write good code around it to avoid its pitfalls; but if your are not sure about your understanding of its limits, use strlcpy.

My understanding of the limitations of strncpy and strlcpy is that you can do something very bad with strncpy (buffer overflow), and the worst you can do with strlcpy is to loose one char in the process.

Solution 4

You should always the standard function, which in this case is the C11 strcpy_s() function. Not strncpy(), as this is unsafe not guaranteeing zero termination. And not the OpenBSD-only strlcpy(), as it is also unsafe, and OpenBSD always comes up with it's own inventions, which usually don't make it into any standard.

See http://en.cppreference.com/w/c/string/byte/strcpy

The function strcpy_s is similar to the BSD function strlcpy, except that strlcpy truncates the source string to fit in the destination (which is a security risk)

  • strlcpy does not perform all the runtime checks that strcpy_s does
  • strlcpy does not make failures obvious by setting the destination to a null string or calling a handler if the call fails.
  • Although strcpy_s prohibits truncation due to potential security risks, it's possible to truncate a string using bounds-checked strncpy_s instead.

If your C library doesn't have strcpy_s, use the safec lib. https://rurban.github.io/safeclib/doc/safec-3.1/df/d8e/strcpy__s_8c.html

Share:
35,013

Related videos on Youtube

hari
Author by

hari

Updated on April 04, 2020

Comments

  • hari
    hari about 4 years

    what should I use when I want to copy src_str to dst_arr and why?

    char dst_arr[10];
    char *src_str = "hello";
    

    PS: my head is spinning faster than the disk of my computer after reading a lot of things on how good or bad is strncpy and strlcpy.

    Note: I know strlcpy is not available everywhere. That is not the concern here.

  • hari
    hari over 12 years
    Thanks for explanation. How can I loose one char in strlcpy? can you please explain?
  • hari
    hari over 12 years
    Thanks. When you say "strncpy is never the right answer when you are working with zero-terminated strings", you mean the source string or dest?
  • jfg956
    jfg956 over 12 years
    If you use strncpy to copy a string larger than your buffer, it will not put a '\0' at the end of the buffer. If you use strlcpy, the '\0' will be there, but one less char will be in your buffer. So if someone used strncpy when he should have used memcpy, using strlcpy instead of strncpy will loose him a char.
  • hari
    hari over 12 years
    Thanks. So when using strlcpy only thing you need to take care is, you should provide destination with (src_length + 1 for null). Correct?
  • jfg956
    jfg956 over 12 years
    Not exactly. The very important thing is to give at most dst size in the 3rd argument to avoid buffer overflow. From there, if this 3rd argument is at least src_length + 1, no char will be lost in the copy. Maybe you want the src to be truncated, and this will be happening if the 3rd argument is less than src_length + 1. But be careful, to truncate str to 5 chars, the 3rd argument should be 6, and dst size must be at least 6 to avoid buffer overflow.
  • hari
    hari over 12 years
    Truncation is not really important to me. What I Want to make sure is, it should fully copy with a NULL at the end. To make sure this, should I provide src_length + 1 all the time? (just to be sure?)
  • jfg956
    jfg956 over 12 years
    Yes, to copy a string of len chars ("hello" is of size 5), you need a buffer of len+1 chars.
  • AnT stands with Russia
    AnT stands with Russia over 12 years
    @hari: The destination string. strncpy is a conversion function, which converts zero-terminated source string to a non-terminated fixed-width target string.
  • hari
    hari over 12 years
    So, If my destination string is char dst_arr[10]; that is not null-terminated. Then I should use strlcpy correct?
  • AnT stands with Russia
    AnT stands with Russia over 12 years
    @hari: Er... I don't understand the question. It doesn't matter what your dst_arr is originally. Originally it is just a block of raw uninitialized memory. The question is what you want do create in that dst_arr. I assumed that you want to create a standard ordinary zero-terminated string in dst_arr (since you said that you wanted to copy an ordinary zero-terminated string to it). If so, use strlcpy. If instead you want to create a "fixed-width string" in dst_arr (which is rather unusual, since most of the time nobody ever uses fixed-width strings these days), use strncpy.
  • hari
    hari over 12 years
    My bad. I do want standard ordinary zero-terminated string. Thanks much for your help.
  • Jim Balter
    Jim Balter over 12 years
    @hari No, that is wrong. The point of strlcpy is to avoid overflow of the output buffer. That means that the size argument is the size of the destination buffer, not the source buffer ... precisely, it is the amount of space remaining in the destination buffer. If you "provide src_length + 1 all the time", your code will be riddled with buffer overflow bugs.
  • Jim Balter
    Jim Balter over 12 years
    strncpy is almost never the right thing, as it zero-fills but does not zero-terminate. The OP wants strlcpy, which zero-terminates and does not zero-fill. Also, it is a mistake to talk about "in this case", because the question of course just an illustration ... real code is not going to be copying a fixed string like "hello" to a fixed sized buffer known to be bigger.
  • Jim Balter
    Jim Balter over 12 years
    strlcpy can be used for the OP's needs.
  • hari
    hari over 12 years
    Jim Balter: got that. I realized that from @AndreyT 's response. Thanks anyways. Appreciate your inputs.
  • greggo
    greggo over 8 years
    I'd add that strncpy doesn't require the source string to be null-terminated. If it doesn't find a nul in n chars, it stops looking. But it treats a nul as a termination if it finds it in the first n chars. unlike strlcpy, which always needs to find the nul at the end of s, so that it can return strlen(s).
  • rurban
    rurban over 6 years
    It is a bit safer, but also not safe. E.g. strlcpy truncates the source string to fit in the destination, which is a security risk.
  • rurban
    rurban over 6 years
    strlcpy truncation is not safe, it's a security risk. safe would be the safe C11 variant strcpy_s().
  • chux - Reinstate Monica
    chux - Reinstate Monica over 3 years
    sprintf(dst_arr,"%.*s",(sizeof dst_arr)-1,src_arr); is UB when sizeof (int) differs from sizeof (size_t). printf(dst_arr,"%.*s",(int) (sizeof dst_arr - 1),src_arr); is a step in the right direciton.