On Tue, Nov 7, 2023 at 8:21 AM Alejandro Colomar <alx@xxxxxxxxxx> wrote: > On Tue, Nov 07, 2023 at 11:52:44AM +0000, Jonny Grant wrote: > > We see things differently, I'm on the C standard side on this one. Would any information change your mind? > > It's difficult to say, but I doubt it. But let me ask you something: > In what cases would you find strncpy(3) appropriate to use, and why? > Maybe if I understand that it helps. > > Kind regards, > Alex Man pages aren't read only by people writing new code, but also by people reading and modifying existing code. And despite your preferences regarding which functions ought to be used to produce strings, it's a widespread (and correct) practice to produce a string from the character sequence created by strncpy(3). There are two ways of doing this, either by setting the last character of the destination buffer to null if you want to produce a truncated string, or by testing the last character against zero if you want to detect truncation and raise an error. I'm not aware of any alternative to a strncpy(3)-based snippet for producing a possibly-truncated copy of a string, except for your preferred strlcpy(3) or stpecpy(3), which aren't available to anyone without a brand-new glibc (nor, by extension, any applications or libraries that want to support people without a brand-new glibc, nor any libraries that want to support other platforms like Windows with only ISO C and POSIX-ish functions); snprintf(3), which has the insidious flaw of not supporting more than INT_MAX characters on pain of UB, and also produces a warning if the compiler notices the possible truncation; or strlen(3) + min() + memcpy(3) + manually adding a null terminator, which is certainly more explicit in its intent, and avoids strncpy(3)'s zero-filling behavior if that poses a performance problem, but similarly opens up room for off-by-one errors. For the sake of reference, I looked into a few big C and C++ projects to see how often a strncpy(3)-based snippet was used to produce a truncated copy. I found 18 instances in glibc 2.38, 2 in util-linux 2.39.2 (in spite of its custom xstrncpy() function), 61 in GNU binutils 2.41, 43 in GDB 13.2, 1 in LLVM 17.0.4, 7 in CPython 3.12.0, 99 in OpenJDK 22+22, 10 in .NET Runtime 7.0.13, 3 in V8 12.1.82, and 86 in Firefox 120.0. (Note that I haven't filtered out vendored dependencies, so there's a little bit of double-counting.) It seems like most codebases that don't ban strncpy(3) use a derived snippet somewhere or another. Also, I found 3 instances in glibc 2.38 and 5 instances in Firefox 120.0 of detecting truncation by checking the last character. So these two snippets really are widespread, especially among the long tail of smaller C and C++ applications and libraries that don't perform enough string manipulation that it warrants creating a custom set of more- foolproof wrapper functions (at least, in the opinion of their authors). Thus, since they're not going away, it would be useful for anyone reading the code to understand the concept behind how these two snippets work, that the only difference between the strncpy(3)'s special "character sequence" and an ordinary C string is an additional null terminator at the end of the destination buffer. In other words, strncpy(3) doesn't create a truncated string, but it creates something which can be easily turned into to a truncated string, and that's its most relevant quality for most of its uses in existing code. Further, apart from snprintf(3), there's no other portable way to produce a truncated string without manual arithmetic. Thus, I'd also find it reasonable to highlight precisely why strncpy(3)'s output isn't a string (viz., the lack of a null terminator), instead of trying to insist that its output is worlds apart from anything string-related, especially given the volume of existing correct code that belies that notion. Or, to answer your question, "It's appropriate to keep using strncpy(3) in existing code where it's currently used as part of creating a truncated string, and it's not especially inappropriate to use strncpy(3) in new code as part of creating a truncated string, if the code must support platforms without strlcpy(3) or similar, and if the resulting snippets are few enough and well-commented enough that they create less mental load than creating and maintaining a custom helper function." (As an aside, I find the remark in the man page that "It's impossible to distinguish truncation by the result of the call" extremely misleading at best, since truncation can easily be distinguished by inspecting the last output character.) Thank you, Matthew House