Protecting the world

from criminally bad code

strncpy

Synopsis

#include <string.h>

char* strncpy(char* restrict s1, const char* restrict s2, size_t n);

Description

The strncpy function copies a null-terminated string from one location to another. Unlike strcpy it takes account of the size of the destination buffer, and is therefore less prone to buffer overflow errors.

Pitfalls

Loss of terminating zero

If the string is too long to fit in the destination buffer then it is truncated. A terminating zero is not added in this case[1], so if you want there to be one (as you almost certainly do) then you must put it there yourself.

The simplest way to do this is to write a zero to the last byte of the buffer after calling strncpy:

strncpy(s1,s2,n);
if (n>0) {
    s1[n-1]=0;
}

If the string was truncated then this will cause it to be terminated (unless the capacity of the buffer is zero, in which case termination is impossible). If there was no truncation then setting the last byte to zero has no effect, because strncpy will already have zeroed it.

Overlapping source and destination buffers

The behaviour of strncpy is undefined if the source and destination buffers overlap[2]. If there is a risk of this happening then the best alternative is likely to be using strlen in combination with memmove, as described below.

Padding of unfilled space with zeros

If the destination buffer is larger than necessary then any unused space will be filled with zeros[3]. This is usually unnecessary and may have an adverse effect on performance.

Limitations

Termination takes no account of multi-byte character encodings

If the string to be copied uses a multi-byte character encoding such as UTF-8 then it could be truncated in the middle of a character.

To avoid this you would either need to ensure that the buffer is large enough to accommodate the string, or use a string copying function that takes account of the character encoding.

Alternatives

Using snprintf

It is possible to use snprintf as a safe alternative to strncpy:

snprintf(s1,n,"%s",s2);

The main drawback of this approach is the extra work that must be done by snprintf to parse the format string. This can be set against the time saved by not unnecessarily padding the destination buffer with zeros, so under favourable conditions (copying short strings into large buffers) snprintf can be expected to outperform strncpy by a wide margin. However, in the case where the strings and buffers are short (which is not an implausible workload) snprintf is likely to be significantly slower, and for this reason it cannot be recommended as a universal replacement for strncpy.

Using strlen and memmove

The standard library does not provide a strnmove function analogous to memmove, so it is necessary to improvise if there is a risk that the source and destination strings might overlap. One way to do this is by using strlen and memmove:

  1. Measure the length of the string to be copied using strlen.
  2. If the string is too long for the space available then reduce the length by the appropriate amount.
  3. Copy the string to its intended destination using memmove.
  4. Terminate or pad the destination buffer as required.

Options are to fully reproduce the behaviour of strncpy:

char* strnmove(char* s1,const char* s2,size_t n) {
    size_t m=strlen(s2);
    if (m>n) {
        m=n;
    }
    memmove(s1,s2,m);
    if (m<n) {
        memset(s1+m,0,n-m);
    }
    return s1;
}

or to rectify its less useful characteristics by arranging for the result to be terminated but not padded:

char* strnmove(char* s1,const char* s2,size_t n) {
    if (n>0) {
        size_t m=strlen(s2);
        if (m+1>n) {
            m=n-1;
        }
        memmove(s1,s2,m);
        s1[m]=0;
    }
    return s1;
}

Portability

  •  C90
  •  C99
  •  C++98
  •  C++11

In C++, use of the header <string.h> is deprecated in favour of <cstring>.

Notes

  • [1] Implied by C99 §7.21.2.4 ¶2
  • [2] C99 §7.21.2.4 ¶2
  • [3] C99 §7.21.2.4 ¶3

Further reading

  • The strncpy function, Programming languages — C, ISO/IEC 9899:1999, §7.21.2.4, p325
  • strncpy, The Open Group Base Specifications, Issue 7, The Open Group, 2008
  • strncpy(3), Linux Programmer’s Manual, The Linux man-pages project
  • Copying and Concatenation, The GNU C Library Reference Manual, The GNU Project