On 10/11/2023 20:19, Alejandro Colomar wrote: > Hi Paul, > > On Fri, Nov 10, 2023 at 07:36:33PM +0100, Alejandro Colomar wrote: >> Hi Paul, >> >> >> On Fri, Nov 10, 2023 at 09:58:42AM -0800, Paul Eggert wrote: >>> On 2023-11-10 03:05, Alejandro Colomar wrote: >>>> Hopefully, it won't be so bad in terms of performance. >>> >>> It's significantly slower than strncpy for typical use (smallish fixed-size >>> destination buffers). So just use strncpy for that. It may be bad, but it's >>> better than the alternatives you've mentioned. You can package strncpy >>> inside a [[nodiscard]] inline wrapper if you like. >>> >>> More importantly, the manual should not push strlcpy as being superior or >>> being in any way a "fix" for strncpy's problems. strlcpy is worse than >>> strncpy in important ways and besides - as mentioned in the glibc manual - >>> neither function is a good choice for string processing. >> >> Hmmmm, that sounds convincing. How about this as a starting point? > > Something slightly better: > > diff --git a/man3/stpncpy.3 b/man3/stpncpy.3 > index 3cf4eb371..8ffedae01 100644 > --- a/man3/stpncpy.3 > +++ b/man3/stpncpy.3 > @@ -67,6 +67,88 @@ .SH DESCRIPTION > } > .EE > .in > +.\" > +.SS Producing a string in a fixed-width buffer > +Programs should normally avoid arbitrary string limitations. > +However, some programs may need to write strings into fixed-width buffers. > +.P > +Although this function wasn't designed to produce a string, > +it can be used with appropriate care for that purpose. > +There are two main cases where it can be useful: > +.IP \[bu] 3 > +Copying a string into a new string in a fixed-width buffer, > +preventing buffer overflow. > +.IP \[bu] > +Copying a string into a new string in a fixed-width buffer, > +with truncation. > +.P > +Using > +.BR strncpy (3) > +in any of those cases is prone to several classes of bugs, > +so it is recommended that you write a wrapper function > +that encloses all the dangers. Some feedback about last line: "that covers all the risks" is clearer. > +.TP > +Copying a string preventing buffer overflow > +.in +4n > +.EX > +[[nodiscard]] > +inline ssize_t > +strxcpy(char *restrict dst, const char *restrict src, char dsize) > +{ > + char *p; > + > + if (dsize == 0) > + return -1; > + > + p = stpncpy(dst, src, dsize); > + if (dst[dsize - 1] != '\0') > + return -1; > + > + return p - dst; > +} > +.EE > +.in > +.P > +If it returns -1, > +the contents of > +.I dst > +are undefined, > +and the program should handle the error. > +.P > +You could implement a similar function in terms of > +.BR strlen (3) > +and > +.BR memcpy (3), > +or in terms of > +.BR strlcpy (3), > +and it would be simpler, > +but this implementation is faster. I suggest to add a little more information, could append "because it accesses less memory". > +.\" > +.TP > +Copying a string with truncation > +Truncation is almost always a bug. > +However, in the few cases where it is not a bug, > +you can use the following function. > +.in +4n > +.EX > +inline ssize_t > +strtcpy(char *restrict dst, const char *restrict src, char dsize) > +{ > + char *p; > + > + if (dsize == 0) > + return -1; > + > + p = stpncpy(dst, src, dsize); > + if (dst[dsize - 1] != '\0') { > + dst[dsize - 1] = '\0'; > + p--; > + } > + > + return p - dst; > +} > +.EE > +.in > .SH RETURN VALUE > .TP > .BR strncpy () > > > However, note how many branches we need to make a function that handles > all corner cases. Is it still faster than strnlen+memcpy? stpncpy must > be heavily optimized for that. Also, strnlen(3) might be optimized out > by the compiler in many cases, so maybe in real code it would be better > to use memcpy. I'd very much like to see some numbers. A benchmark test would show performance. Can't be that many lines of code in a loop to measure this. strnlen_s is in the C standard Annex K, but strnlen didn't make it in yet, even C23. Kind regards Jonny