Path: csiph.com!news.mixmin.net!eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Keith Thompson Newsgroups: comp.lang.c++ Subject: Re: Never use strncpy! Date: Wed, 21 Sep 2022 16:01:11 -0700 Organization: None to speak of Lines: 69 Message-ID: <874jx0fi2w.fsf@nosuchdomain.example.com> References: MIME-Version: 1.0 Content-Type: text/plain Injection-Info: reader01.eternal-september.org; posting-host="b6dd3111f3087e08fb468b174c9193d6"; logging-data="2031421"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19f5av0hlQs+ljPHbU3CT/m" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.2 (gnu/linux) Cancel-Lock: sha1:T2bWwU3EbTTJxPaE07ONw6bkP8M= sha1:aZSjF7Iam67QLTYF2STPEb19VB4= Xref: csiph.com comp.lang.c++:86474 Juha Nieminen writes: > Well, *almost* never, at least. > > I always thought that std::strncpy() works exactly like std::strcpy(), > except that it stops early if the specified count is reached. Turns out > that I was gravely mistaken: > > "If, after copying the terminating null character from src, count is not > reached, additional null characters are written to dest until the total > of count characters have been written." > > This means that if you have, let's say, a 1 MB buffer into which you copy > with std::strncpy() lots and lots of strings, the vast majority of them > very short, expecting it to be efficient... turns out you'll be writing > 1 MB worth of data every single time. Which will make the thing quite > slow if you weren't aware of this. > > It's just better to do your own custom version of strncpy() that does > what strncpy() should be doing, ie. just stop once the source string > ends. > > I can't find any standard library (C or C++) function that does that, > so you'll just have to write your own. (Luckily it's trivial to do.) > > And while you are at it, you might also want to fix this little problem: > > "If count is reached before the entire string src was copied, the > resulting character array is not null-terminated." > > Perhaps return to the caller some value telling if the string was > truncated. (Replying in part to things that have been said in other posts in this thread.) strncpy() is not poorly designed. It's quite reasonably designed for the niche purpose for which it was intended, where the source is an ordinary null-terminated string and the target, an N-byte character array, hold a sequence of M significant non-null characters followed by exactly N-M null characters. It is poorly *named*. The name implies that, as strncat is a "safer" strcat, strncpy is a "safer" strcpy. Both strncat and strncpy let you specify the size of the target array, avoiding writing past the end of it, but strncpy treats its target as null-terminated string. I wrote about strncpy here (a lot of what I write has been covered in this thread): http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html Of course this is comp.lang.c++, so you should usually be using std::string, but sometimes you do need to deal with C-style strings. It's unlikely (but still possible), that strncpy() might be the right tool for the job. If it is, thoroughly comment the code so that the next person who maintains it doesn't break your assumptions. A digression: Quietly truncating the output, as strncpy and strncat do, is not always "safer". Sometimes it's exactly what you want, for example if you're printing data in fixed-width columns and it's going to be obvious that something has been truncated. Sometimes silent truncation can be worse than terminating the program, for example if a command string "rm -rf $HOME/tmpdir" is quietly truncated to "rm -rf $HOME/". If your code handles errors, always think about what that error handling will actually do. -- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com Working, but not speaking, for Philips void Void(void) { Void(); } /* The recursive call of the void */