strcpy() was replaced with a safer strncpy() and in turn has been replaced with strlcpy().
The list is a ban of the less safe versions, where more modern alternatives exist.
strcpy() was replaced with a safer strncpy() and in turn has been replaced with strlcpy().
The list is a ban of the less safe versions, where more modern alternatives exist.
http://the-flat-trantor-society.blogspot.com/2012/03/no-strn...
Was it intended for fixed length records?
You can also use it to overwrite part of an existing string, but I think that’s a side effect of the above.
struct dir
{
char name[14];
int inode;
};
Adding a NUL byte might waste a full byte that could otherwise be used---remember, back when C was first developed, 10M disks were large and very expensive.As you say, it does in fact obviate some errors. A value judgement as to which behaviors are more or less safe may be subjective, but the intent is not.
To be clear, strncpy does not guarantee NUL termination. It takes a C string as the source argument, but it doesn't write out a C string; it writes out a very esoteric data structure that is unfortunately easily confused with a C string.
By contrast, strlcpy was intended to be a safer string copy routine: https://www.usenix.org/legacy/event/usenix99/full_papers/mil... In particular, it was designed to be what people seem think strncpy is. Its return value semantics are controversial, though mostly only among the glibc crowd as every other Unix libc, including musl and Solaris, now provide it. But the semantics were designed based on experience in fixing old C code, and observations about how developers tend to write C code, not based on prescriptive theories about how people should manipulate C strings in C code.
There's a QNX user process that's always present, called "proc", which handles pathnames and the "resource managers", programs which respond to path names. But that's in user space, and has all the tools of a user-space program.
When handling strings in C, it's useful to use the string functions from glib or pull in one of the specifically safe string handling libraries and not use any C stdlib functions for strings at all.
There are a number of C strings libraries safer to use than the standard library, and many of them are simpler, more feature-rich, or both.
* https://github.com/intel/safestringlib (MIT licensed)
* https://github.com/rurban/safeclib (MITish)
* https://github.com/mpedrero/safeString (MIT licensed)
* https://github.com/antirez/sds (BSD 2-clause, and gives you dynamic strings)
* https://github.com/maxim2266/str (BSD 3-clause)
* https://github.com/xyproto/egcc (GPL 2.0, includes GC on strings)
* https://github.com/composer927/stringstruct (GPL 3.0)
* https://github.com/c-factory/strings (MIT licensed)
* https://github.com/cavaliercoder/c-stringbuilder (MIT licensed, does dynamic)
If one does use the C standard library directly for handling strings, the advisories from CERT, NASA, Github, and others should be welcome advice (CERT's advice, BTW, includes recommending a safer strings library right off).
And yes: it should all still compile, but none of that prohibits the compiler from issuing flashing red/yellow warning messages to your terminal for using footgun functions, preferably with uncomfortable audible notifications too.
All of this is silly though, because even in a strict C89 environment you can still have your own safe wrappers over the unsafe functions. I find that very little of modern programming has a hard dependency on ultramodern compiler features (e.g. you can theoretically build React/Redux using only ES3 (1998ish) if you like. Generics using type-erasure can be implemented with macros. Etc.).
Also, C89 conformance doesn’t mean much: you can have a confirming C89 system that doesn’t even have a heap - nor a stack for autos! (IBM Z/series uses a linked-list for call-frames, crazy stuff!)
When updating existing code C89 (maybe K&R) might be what's used so minor code changes won't undo that.
I tend to write most of my code in something higher-level than C and only resort to C or assembly in performance-critical sections as found with a profiler. Plenty of general-purpose languages have memory-safe strings built into the language, and honestly I keep hoping the Cisco/Intel safestrings library or something like SDS gets the standard library blessing one day.
Why stop there? Don't use C. Use Rust!
When it is possible, I certainly agree that Rust is nicer.
As long as it is done like in recent versions of Visual C++ where i can disable that useless compiler output pollution with a #define, usually with a snide remark about Visual C++ right above it.
The compiler is trying to help you write better code - suppressing warnings should not be taken lightly.
As i wrote in another comment, something that may lead to issues isn't the same as something that will always lead to issues - e.g. if i check a string's length or actually calculate and allocate the necessary memory before calling strcpy it is perfectly fine and safe to use it, but Visual C++ doesn't know about that, it complains like some stupid greenhorn that read somewhere "never use gotos" and then is surprised when he sees some Linux kernel code with gotos everywhere for cleanup, thinking that those people writing the kernel do not know what they're doing.
Removing strcpy would make the Python transition look easy.
The reality of C is that if we deprecated every objectionable function in the stdlib we wouldn't have anything left.
I think you mean there are very few functions that cannot possibly be used correctly (namely gets). Most C functions are dangerous - can lead to crashes and security vulnerabilties if used incorrectly - but that's just a expected consequence of using a language with no provisions for memory-safety.
> The reality of C is that if we deprecated every objectionable function in the stdlib we wouldn't have anything left.
Somewhat ironically, malloc is actually perfectly safe[0] - using the return value has some issues, but calling it is always[0] fine.
0: Assuming the OS-level memory allocator is sanely configured WRT overcommit, anyway.
Its nearly the exact same reasoning as "we're not going to break older websites"
Runtime backwards compatibility is similarly extensive on platforms that care about it. You can still take a DOS app written in ANSI C89 the year that standard was released, and run it on (32-bit) Windows 10, and it'll work exactly the same. In fact, you can do this with apps all the way back to DOS 1.0.
Also in many systems the C library is linked dynamically and shared among all programs so even though a program is compiled it still relies on the underlying system to provide the function.
Finally i'm certain that if a C standard removes something, it'll be treated as the equivalent to that standard not existing. C programmers are already a conservative bunch without such changes.
size_t strlcpy(char *dst, const char *src, size_t dstsize)
{
size_t len = strlen(src);
if(dstsize)
*((char*)mempcpy(dst, src, min(len, dstsize-1))) = 0;
return len;
} *((char*)mempcpy(dst, src, min(len, dstsize-1))) = 0;
can be replace by ((char*)memcpy(dst, src, min(len, dstsize-1))[min(len, dstsize-1)] = 0;
if you don't have mempcpy