> But in practice, people tend to ignore the return value (which is using the functions incorrectly)

That might be true. It would be very interesting to see some statistics. However, with these functions, it is very easy to check whether the truncation detection is being done or not. Grep is mostly enough, but it can even be automated for most cases.

Also, that is hardly an argument against these functions: any string utility function will inevitably have to deal with errors somehow (or worse, ignore them and continue!).

> if you were used to strncpy (which has its own performance problems), you might wrongly assume that you could use these to pull substrings out as well.

Yes, and sadly I've seen something like that (and worse) in the wild. These are easy to spot though.

> Sorry, but it is not wrong.
>
> See the actual implementation source: http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/st....
>
> "Returns strlen(src) + MIN(siz, strlen(initial dst))."

Interesting. You're right about the code and its return value. However, the current manual documents it a little bit differently; the weird return value for the case when the initial destination string is not a string is never mentioned (but the fact that NUL-termination won't occur in this case is there). So in practice you can forget the MIN() and say it is strlen(dst) + strlen(src). From my perspective it makes all the sense, because, going back to what I've argued before, a string handling function should at least be allowed to assume you're giving it strings to work with; it's not there to validate your input or check pointers, etc.

> Even the official man page says the return value is confusing: "While this may seem somewhat confusing, it was done to make truncation detection simple."

You quoted a line that is not describing the corner-case return value mentioned above. It is describing the fact that the return value is (assuming actual strings are processed!) the total length of the string that would result from the operation if the destination buffer was large enough to hold it without truncation. There is nothing confusing about that. Perhaps the author initially thought it would be confusing for people who expect it to resemble functions such as read() that return the number of characters actually given to you. But there is nothing to be confused for, and the official man page has been simplified to reflect that:

commit: http://marc.info/?l=openbsd-cvs&m=133338810915771&w=2
current version: http://mdoc.su/o/strlcat

> I mean no disrespect, but you're proving my point. Even most proponents of these functions do not understand all of the nuances in how they work. That's a real problem, as if you don't understand strlcat's return value, you can't use it safely.

The correct way to detect truncation with strlcpy and strlcat has always been exactly the same, and documented:

if (strlcat(dst, src, dstsize) >= dstsize) { /* truncated */ }

The fact that I wasn't aware of a corner-case scenario where dst does not contain a string to begin with has in no way impeded my ability to type the above line correctly. The branch will still be taken if the string would be too large for the buffer, but your code is broken and strlcat cannot fix it for you.

> The functionality is too specialized to be general purpose functions

Yes, they perform a very specific function; they are not Perl. Yet these are "general purpose" enough that the less secure variants (and not only these as of C11) were introduced in the C standard, and are used everywhere. These functions are convenient, available everywhere, and recognized by any C programmer, and that is why they are used. The OpenBSD functions came to be because of the widespread (mis)use of the C functions, to make it easier to do it right.

> Exactly. They're useful functions for certain purposes. My only point is that they are by no means perfect. There are many use cases where they are not appropriate. Unfortunately people tend to either praise this family as the solution to C memory safety problems, or they dismiss them entirely.

Good to know we are in agreement. :-) Perhaps I interpreted you too strongly when you said one may as well use another implementation; to me that sounded like a suggestion to dismiss these entirely.

> These are all the programmer's fault for misusing the functions, of course, but safer and/or more versatile functions can be made.

I would be interested in a concrete example. More versatile? Yes, that is easy. Safer? Well I'm not so sure about that. Perhaps by trading some correctness. Perhaps in some non-critical user-land application where unbounded allocations are OK and aborting on memory exhaustion is "safe". Simpler and safer? Almost definitely not, but please show me I'm wrong :-)