If there are bugs with truncation in the resulting buffer, those are the program's bugs, and they existing before strlcpy(3) came into the picture.
If there are bugs with truncation in the resulting buffer, those are the program's bugs, and they existing before strlcpy(3) came into the picture.
It's not a drop-in replacement, though. Not even if you ignore the different return type.
strncpy guarantees that the buffer will be completely overwritten (filling with null chars at the end), while strlcpy will happily leave remnants of whatever was there before.
Just dropping in strlcpy wherever strncpy appears can lead to data leaks or inconsistent hashes, for example, depending on how the buffer's contents are used.
"No true Scotsman..."
A truncation bug is a hell of a lot easier to debug than memory corruption.
LOL. It does not force anything - you can mishandle source or destination buffer lengths very easily and compiler won't say anything.
I sometimes wonder what kind of disaster will have to happen to make C programmers agree on a standard buffer (i.e. pointer+size) type with mandatory runtime bounds enforcement ....
I think a lot of the confusion in the C string discourse comes from people thinking they should rely on the NULL termination byte for string length. You really shouldn't, and if you have to do it, you need to be extra careful to check all your assertions that it will be properly terminated. Just carry around the length, and bundle it with the pointer in a struct to pass it around when it makes sense. Not the most ergonomic, but it's C, what can ya do.
Nowadays, things like C++ string_view's and Rust str slices handle this for you automatically, but those came around much later and require more sophistication at compile time.
Nitpick: it’s not quite a drop-in. Prototypes of these functions are
char * strncpy(char *dst, const char *src, size_t num);
size_t strlcpy(char *dst, const char *src, size_t num);
strncpy(dst, src, num) always returns dst (https://cplusplus.com/reference/cstring/strncpy/), which is quite useless, as the caller knew that already.strlcpy(dst, src, num) returns the total length of the string it tried to create (https://www.unix.com/man-page/posix/3/strlcpy/). Callers can use that to detect that the string didn’t fit the buffer and reallocate a buffer that’s long enough.
The reason for the existence of strlcpy isn’t that it is perfect, it’s that it’s the best option with good UX for integration into an existing C code base.