flawopen.com/Memory Safety/strcpy vs strncpy

Is strncpy() safer than strcpy()?

CWE-787: Out-of-bounds WriteReference page
Short answer

Safer, but not safe — and it is misused so consistently that it causes its own bug class. strncpy() will not overflow the destination, but it does not guarantee a null terminator. If the source is exactly as long as the buffer, you get an unterminated string, and the next function to read it runs off the end.

BOTH ARE WRONG
char dst[16];

/* 1. Unbounded — classic overflow */
strcpy(dst, src);

/* 2. Bounded, but may not terminate.
   If strlen(src) >= 16, dst has no
   '\0' and every later strlen/printf
   reads out of bounds.            */
strncpy(dst, src, sizeof(dst));

/* 3. Off-by-one: room for 16 chars
   plus a terminator = 17 bytes,
   but dst only holds 16.          */
strncpy(dst, src, sizeof(dst));
dst[sizeof(dst)] = '\0';   /* OOB! */
CORRECT
char dst[16];

/* Preferred: snprintf always
   null-terminates (when size > 0),
   and tells you about truncation. */
int n = snprintf(dst, sizeof(dst),
                 "%s", src);
if (n < 0 || (size_t)n >= sizeof(dst)) {
    /* truncated — handle it */
    return ERR_TOO_LONG;
}

/* Or strlcpy where available —
   always terminates, returns the
   length it tried to create.      */
if (strlcpy(dst, src, sizeof(dst))
        >= sizeof(dst)) {
    return ERR_TOO_LONG;
}

What strncpy was actually designed for

Its surprising behaviour is not a defect — it was written for fixed-width record fields, not for strings. If the source is shorter than n, it pads the remainder with null bytes; if the source is longer, it copies exactly n characters and stops, terminator or not. That is correct behaviour for writing into a fixed-size field in a binary format, and the wrong tool for "copy this string safely", which is what it gets used for.

The padding behaviour also makes it quietly inefficient on large buffers, since it writes the full n bytes regardless of how short the source was.

Always check for truncation

Preventing the overflow is only half the job. Silent truncation is itself a security problem: a truncated hostname, path, or authorization value can change meaning rather than simply being shorter. snprintf returns the length it wanted to write, so comparing that against the buffer size detects truncation — the same return-value semantics that, when misread as "bytes written", produced Citrix Bleed.

FAQ

What about strcpy_s and the Annex K functions?

They null-terminate and check bounds, which addresses the problem, but portability is uneven — they are well supported on Windows and patchily implemented elsewhere. If you target multiple platforms, snprintf is the dependable choice.

Is strlcpy in the C standard?

It originated in OpenBSD and is widely available on BSD and macOS, with glibc adding it comparatively recently. Check availability for your targets rather than assuming it.

In C++, should I use any of these?

Prefer std::string and std::string_view, which manage length for you and remove the entire class of bug. Reach for the C functions only at an API boundary that requires a raw buffer.

References