At Sat, 4 Jan 2025 18:42:08 -0500 (EST), Mouse <mouse%Rodents-Montreal.ORG@localhost> wrote: Subject: Re: Usage of strncpy in the kernel > > > strncpy() has the advantage of working nicely and predictably > > regardless of whether the known buffer's length is that of the source > > or that of the destination. I.e. one can use it to copy a known > > number of possibly (or definitely) unterminated chars from an array > > of a given length into an array of the same or larger size; > > Huh? > > If I have an array [N1], NUL-terminated unless length is N1, and I want > to copy that quasi-string into an array [N2], with truncation if src > length > N2 and NUL-termination if src length < N2...I can't see how > strncpy can do that. That's not what I described. Especially not in just that part quoted above. I'm not sure what you're trying to get at. I didn't mention "NUL-termination" once in the above quoted portion. strncpy() itself does not do NUL-termination, unless one conflates that with the filling of the destination with zeros in the case where the source "ends" before 'len' characters have been copied. The zero- filling should not be conflated with NUL-termination, and definitely never be relied upon as an alternative to explicit separate NUL- termination. strncpy() must always copy 'len' characters, and so if the source "ends" before that many have been copied, it continues copying zeros until it is finished This is described arguably better in the POSIX spec than most manual pages (here with NetBSD strncpy(1) parameter names in square brackets): If the array pointed to by s2 [[src]] is a string that is shorter than n [[len]] bytes, NUL characters shall be appended to the copy in the array pointed to by s1 [[dst]], until n [[len]] bytes in all are written. POSIX clarifies the meaning of "a string that is shorter than 'n' bytes" in the paragraph above the quoted one: (bytes that follow a NUL character are not copied) As I said, if one wishes to use the destination array as a C string then one must _always_ manually NUL terminate it explicitly. So as a concrete example of this first scenario I described: struct foo { char name[8]; /* an array with an up-to-8-char name */ } src = { { '1', '2', '3', '4', '5', /* '6', '7', '8' */ } }; char *dst = malloc(sizeof(src.name) + 1); strncpy(dst, src.name, sizeof(src.name)); dst[sizeof(src.name)] = '\0'; printf("dst = '%s'\n", dst); Note how the 'len' is specified as the size of the source array, and the programmer makes sure the destination is larger than that. Now a concrete example for the alternate scenario I described: size_t srclen; char *longsrc = fgetln(stdin, &srclen); char *nln = NULL; struct foo { char name[8]; /* an array with an up-to-8-char name */ } dst; if (longsrc[srclen - 1] == '\n') { longsrc[srclen - 1] = '\0'; } else if (srclen > 0) { nln = malloc(srclen + 1); /* pedantically add a NUL in case input is < 8 chars */ memcpy(nln, longsrc, srclen); nln[srclen] = '\0'; longsrc = nln; } else { exit(1); /* EOF on input */ } strncpy(dst.name, longsrc, sizeof(dst.name)); if (nln) free(nln); Note how 'len' here is now specified as the size of the destination array, which is not going to be used as a string so it is not NUL-terminated (but it may end up being a string shorter than 8, though the whole of the array will have been filled with valid data). -- Greg A. Woods <gwoods%acm.org@localhost> Kelowna, BC +1 250 762-7675 RoboHack <woods%robohack.ca@localhost> Planix, Inc. <woods%planix.com@localhost> Avoncote Farms <woods%avoncote.ca@localhost>
Attachment:
pgpvvmdpnXnPY.pgp
Description: OpenPGP Digital Signature