Strncpy() is not a “safer” strcpy()
the-flat-trantor-society.blogspot.com
the-flat-trantor-society.blogspot.com
So yes, it is safer. You would be mad not to use it.
snprintf(buffer, size, "%s", source);
This can be put into a #define macro or inline function.If what you want is a null terminated, truncated copy that fits into a given buffer size, and snprintf is available, you are mad to still use strncpy.
Also, strncpy pads the destination with nulls, if there is remaining space. Because of this, the evident purpose of strncpy is to fill fixed-width text fields in "old school" fixed-field database records. Writing the extra nulls is wasteful if the data type in question is nothing but a C string.
my_string_cpy() < strcpy < strncpy < strncat < snprintf < strlcat
I dislike the strncat approach because if the prior null termination gets lost then problems ensue, whereas with snprintf that won't happen. The BSD man page mentions that snprintf may not be safe for use in signal handlers on some systems; obviously snprintf is a much bigger piece of code.
Personally I dislike using extensive macros, but I'll leave that for the flame war.
diff(1) doesn't seem relevant; it operates on text files, which normally don't contain any null characters.
https://randomascii.wordpress.com/2013/04/03/stop-using-strn...
I tried to give alternatives. Calling strncpy and then manually null-terminating is not a good alternative. Creating a wrapper that does this is better. That wrapper could optionally abort the program on string truncation.
And, probably more importantly, a template wrapper can infer the destination size, thus getting rid of the error-prone specification of the destination size (I have seen it specified incorrectly many times).
You'd be mad to use strncpy when better alternatives are so easy to find or create.
strcpy() can be used safely if you ensure that the destination array is big enough to contain the source string. (Yes, that can be non-trivial.)
strncpy() by itself doesn't write past the end of the destination array (assuming you call it correctly) -- but it can easily leave the destination without a terminating null character. This causes undefined behavior if you then pass the destination array to another string function. strncpy() is not dangerous by itself, but it can leave a booby-trap that causes other string functions to be dangerous.
This:
strncpy(dest, source, size);
can be replaced by this: dest[0] = '\0';
strncat(dest, source, size);
which will leave the destination properly null-terminated.Note that this can still quietly truncate the string. Ignoring that possibility is rarely the right thing to do.
Some insights here: https://msdn.microsoft.com/en-us/library/bb288454.aspx
strncpy example vulnerability experience linked to from that article "Buffer Overflow in Apache 1.3.xx fixed on Bugtraq - the evils of strncpy and strncat!": http://blogs.msdn.com/b/michael_howard/archive/2004/10/29/24...
Source code for MS products are automatically (since SDL) screened for use of the banned functions. You'll have to use the "safer" alternatives.
Opinion: Personally, because I strive to learn more than to be "productive", I prefer languages that force the author to write her own libraries. As I see it, the alternative is languages that discourage this, effectively coercing the author to use other people's libraries, the quality over which she has no control.
Opinion: For me, the bad part is that there are so many poorly thought out C functions in the wild (even including the "standard" ones); the good part is that the C language encourages authors to write their own libraries.
Given the choice, I still prefer assembly to C. I guess this is because I prefer to write small programs; perhaps I am not smart enough to write large ones.
I prefer not to reinvent the wheel when I know my implementation won't be any better, or if I were able to make a better wheel, that will be time spent that I wasn't reinventing the carriage.
Implicit conversion between vectors and pointers should have never happened. I don't get why people find so hard to write &vector[0] for those cases where a pointer is needed.
Also if other languages, for other OS, older than C could do bound checking elision, C not doing it was only saving work for the compiler developer.
The requirement for a cast would be better, because that's the existing notation for explicitly requesting conversions that are identified as unsafe. I.e.
char array[42];
char *p = array; /* error, implicit conversion */
char *q = (char *) array; /* OK */
char *s = &array[0]; /* Sneaky: OK, without a cast */In any way, for me the right way of doing systems programming is the way of Mesa, Modula-2 and many others.
C was already bad in the 70's.
It didn't teach me enough to recognize the silliness in C.
I believe that this is an aspect of C popularity that hasn't received a lot of recognition. Programmers were sucked away from cleaner languages into C, because the users of the cleaner languages had neglected to acquire the body of rationalizations for why those languages are that way which could have helped them stick.
C looked good in naive ways. "Hey, look at all the things you can easily do with memory and pointers! Wow, look at that slick syntax: you can stuff several increments and an assignment into an expression, and use that as the test of a loop, ... man I'm never writing foo := foo + 4; again!"
Modula 2's memory management is basically malloc/free though. While the language could save you from array overruns, it is basically defenseless against leaks and use-after-free bugs, as well as uses of unchecked null pointers under OOM:
See:
http://www.modula2.org/reference/isomodules/isomodule.php?fi...
Look, the allocator works with generic pointers, has an explicit DEALLOCATE, and ALLOCATE returns NIL when there is no memory!
Modula 2' standard also has a SYSTEM module which adds C-like things: pointer arithmetic, casting and whatnot.
http://www.modula2.org/reference/isomodules/isomodule.php?fi...
Is that just "C envy", or is there perhaps need for those things, know what I mean?
Fortunately on the same year I got to learn C++, which allowed me to use most of the features I already knew from Turbo Pascal, alongside better safety if cared about it.
Eventually I only used pure C when required to do so at the university and on my first job after the university. Everywhere else the choice between both languages was always C++.
Regarding C, when coding in it, I always adopted a Turbo Pascal style by using translation units as if they were modules. With data structures designed as ADTs, without any direct access to its internals, defensively programming and eventually with a little bit of design by contract.
> Modula 2's memory management is basically malloc/free though. While the language could save you from array overruns, it is basically defenseless against leaks and use-after-free bugs, as well as uses of unchecked null pointers under OOM:
Yes, but there is already a bit list of errors that Modula-2 and similar languages saves one from:
- Buffer overruns (unless disabled, of course)
- Out parameters being null
- Implicit conversions of enumerations into integers
- Implicit conversions between numeric types
- Strings without terminating null
> Is that just "C envy", or is there perhaps need for those things, know what I mean?
Of course those features are needed in systems programming, but there is a big difference being safe by default and making explicit use of unsafe code, or just being unsafe everywhere.
For example, in Modula-2 if a module imports SYSTEM you already know that module is doing something fishy. In Oberon and Modula-3, like .NET, one could forbid unsafe modules from being loaded.
Whereas in C, even code that looks harmless can be doing strange things to the memory state.
strndup performs identical to strncpy except that it always terminates the destination string. (https://www.gnu.org/software/libc/manual/html_node/Copying-a...)
A grail shelf that wasn't intended as a booby trap would contain one cup, the right one.
/sarcasm
Then again "your C code is valid C++ code!" was perhaps the biggest selling point of C++ when it came out.
And no, std::string is decidedly not a proper "string class".
People often complain about the lack of a real "string class" in the standard C++ library. Well, guess what? No language today really has primitives that handle unicode absolutely perfectly, and there's still intense debate about what they should be doing with respect to encodings, length() functions etc.
Maybe the answer is that Unicode itself should be simplified so that every word in language has one representation in any particular encoding.
std::string is an embarassement. It's both bloated (why, we need to have both iterator-based and index-based access interfaces!) and lacks basic string manipulation functionality, it's encoding-unaware.
- It has all the string manipulation capability of the C standard library
- Being encoding unaware was probably a blessing given how unicode has evolved since std::string was introduced (20-30 years ago?)
If you want to use std::string operations on an array of characters that you don't own or that are part of an indivisible larger structure, you're out of luck.
It's not difficult to craft a slice-like replacement, but range types will be most welcome when they finally hit the standard.
http://en.cppreference.com/w/cpp/experimental/basic_string_v...
I personally now avoid C as much as possible.
People are just as likely to migrate to another language (Rust? Go? Even C++) as upgrade the old C code.
I don't think, that you can discontinue strcpy and co.
The C++ standard seems to get much more attention than C. C seems to be the step-daughter of programming languages, but still so many projects rely simply on standard C (and not C++).
The correct solution, assuming you can't just import libbsd or include its functions, is probably to use snprintf. It goes guarantee null-termination of the target. So
strncpy(dst, src, size_dst);
becomes snprintf(dst, size_dst, "%s", src);
Checking for partial copy is not ideal though, snprintf returns the number of bytes it would have copied had the destination buffer been infinite excluding the final NUL byte. So a copy is only complete if `ret < size_dst`.snprintf is not available in C89 though...
> assuming you can't just import libbsd or include its functions
Just use strncpy and NUL-terminate the buffer. It's not hard. Write a two line function to do it for you, and use that function in place of strncpy.
Just as it's not hard to not dereference null pointers, not double-free allocations and a truckload of other mindless drudgery which history shows humans won't reliably get right all the time. Not to mention checking for copy truncation with strncpy is error-prone, you've got to check whether it points to a `\0` before you manually null-terminate it, providing more chances to get it wrong.
> snprintf is also slower. It has to parse the format string.
How about worrying about that when snprintf actually shows up in profiles and there's no algorithmic way to improve the situation and strncpy is a significant improvement?
Use it once. In a 2-line wrapper. And use the wrapper everywhere.
No human reliability to worry about.
dest[0] = '\0';
strncat(dest, src, size); strncpy(dest, src, size);
dest[size - 1] = '\0';Is there a resource where these issues are answered once and for all, for the novice C programmer? Also, are there deprecation warnings emitted by the compiler for non-safe C stdlib functions?
And then there's this gem:
"...If the source string is 5 characters long, and the target is a 1024-byte buffer, and you set n to the size of the target, strncpy will copy those 5 characters and then fill all 1019 remaining bytes in the target with null characters. Since all it takes to terminate a string is a single null character, this is almost always a waste of time.
Ok, so that's not so bad. CPUs are fast these days, and filling a buffer with zeros is not an expensive operation, right? Unless you're doing it a few billion times, but let's not worry about premature optimization."
Does he think languages with built in String types have some magical optimization juice that make string operations fast? How long does it take to instantiate a new String object, run it's copy constructor, blah blah.
Any C programmer looks to avoid these types of situations.
Unfortunately, that's not the case.
I presume this link was posted here as a result of my recent comment on the "Don't Learn C the Wrong Way" article, which recommends strncpy() and strlcpy() as safer alternatives to strcpy().
I've see a number of calls to strncpy(). I've rarely seen such calls explicitly null-terminate the destination array. I've even seen things like
strncpy(dest, src, strlen(src));
which is certainly no safer than strcpy().What I get out of this particular pedantic rant is an opportunity to let C programmers know that strncpy() isn't what they might thing it is (as well as a mention on the front page of Hacker News!).
No, I don't think that. I didn't mention it because I wasn't talking about languages with built-in String types; I was talking about C.
Unfortunately, it isn't automatic so some times humans will forget to do it.
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *src = "Gobblygook is a long string";
char dest[5];
strncpy(dest, src, sizeof(dest));
dest[sizeof(dest) - 1] = '\0';
printf("src = %s\ndest = %s\n", src, dest);
}
make test
./test
src = Gobblygook is a long string
dest = GobbThis article is also on GH (including some changes): https://github.com/Keith-S-Thompson/the-flat-trantor-society...
But what I would expect is that it would copy len(s2) characters, not n.