6 ms·
Many of C's problems relate to string handling. These are all legacy functions which have been replaced with safe alternatives many decades ago. strcpy() was r
by throwaway09223 6y ago
Many of C's problems relate to string handling. These are all legacy functions which have been replaced with safe alternatives many decades ago.
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.
- ChrisLomont 6y agoThese still lead to lots of bugs via off by one errors on lengths or other buffer misuse.
- cestith 6y agoStill, unless you're writing something that has to be very low-level all the way through, it's better to use a string-handling library than the stdlib tools for strings.
- stefan_ 6y agoThe first thing you do is not use any strings. You'll be amazed how much you can get done in languages that aren't so obsessively centered around stringified programming.
- derefr 6y agoYes, sure, write Unix CLI plumbing tools without strings.
- pjc50 6y agoUntil you want to communicate with the user, filesystem, or web.
- Animats 6y agoIt was a design decision of QNX that the kernel never uses strings. Everything the kernel handles is fixed length, except messages, and messages go from one user process to another. The kernel does not allocate space for them. I think they go that right. 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.
- cestith 6y agoThere are absolutely things that can be written without string handling. Then again, there are things that can't. Not handling strings in the kernel probably was a good decision. That userland I'll bet has string handling though, to be useful to users.
- cestith 6y agoMost of the code I write has a spec of input and output being some form of text. Still, I tend to write that in languages that have safe string handling and drop into C only when the profiler indicates that's useful. 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 https://github.com/intel/safestringlib (MIT licensed) * https://github.com/rurban/safeclib https://github.com/rurban/safeclib (MITish) * https://github.com/mpedrero/safeString https://github.com/mpedrero/safeString (MIT licensed) * https://github.com/antirez/sds https://github.com/antirez/sds (BSD 2-clause, and gives you dynamic strings) * https://github.com/maxim2266/str https://github.com/maxim2266/str (BSD 3-clause) * https://github.com/xyproto/egcc https://github.com/xyproto/egcc (GPL 2.0, includes GC on strings) * https://github.com/composer927/stringstruct https://github.com/composer927/stringstruct (GPL 3.0) * https://github.com/c-factory/strings https://github.com/c-factory/strings (MIT licensed) * https://github.com/cavaliercoder/c-stringbuilder 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).
- _kst_ 6y agostrncpy() is not a "safer" strcpy(). It can avoid some errors involving writing past the end of the target array (if you tell it the correct length for that array), but it's not a true string function, and it can leave the target unterminated and therefore not a valid string. http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html http://the-flat-trantor-society.blogspot.com/2012/03/no-strn...
- icedchai 6y agoThis is true, and many people don't realize it. I used to call a wrapper function that would always set the last byte to 0.
- rrauenza 6y agoI never could really understand the point of strncpy()... we always end up wrapping to deal with writing an unterminated string. Was it intended for fixed length records?
- tedunangst 6y agoIt is for fixed length records, which is why it also zeroes the remaining space.
- ironmagma 6y agoArguably naming it with “str” is itself a security vulnerability.
- tedunangst 6y agoNo argument. At best it is a "string to fixed record" function, hence the name, but it is not a string function.
- Someone 6y agoYes. strncpy was intended for copying file names into a buffer that was only zero terminated when the name was shorter than the maximum length of a file name in Unix (14 bytes. See https://stackoverflow.com/a/1454071 https://stackoverflow.com/a/1454071, https://devblogs.microsoft.com/oldnewthing/20050107-00/?p=36773 https://devblogs.microsoft.com/oldnewthing/20050107-00/?p=36...) You can also use it to overwrite part of an existing string, but I think that’s a side effect of the above.
- Kaze404 6y agoWhy are these functions deprecated in favor of others but not removed? I know in Javascript this can happen so as to not break older websites, but in a compiled language this shouldn't be a problem right?
- lalaithion 6y agoThe expectation of a C89 programmer is that a valid C89 program can be compiled for any machine that has a C89 compiler, and likewise for C95, C99, C11, and C17. Furthermore, it's expected that any C89 program can be compiled unchanged on any future version of C, and the standard library is part of the definition of the language, and therefore functions cannot be removed.
- DaiPlusPlus 6y agoAt a certain point we have to say that it’s wrong for someone to expect C89 should still be the LCD. 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!)
- cestith 6y agoI think for new code in environments that support newer standards C89 shouldn't be used. For the increasingly rare places new C is being written where C89 is the latest tooling available and the code handles strings, a safer string library is nearly a must. I strongly recommend a safer string library no matter which standard, but I'm nobody. 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.
- pix64 6y agostrlcpy() isn't standard. You have to provide your own implementation if you want your code to be portable.
- cestith 6y agoThis is something git does. That's why they prefer it - it's available to git everywhere.
- schlupa 6y agoIt's 4 lines of code to implement it. So even if it is not available on a platform (glibc mmmh because of Dreppers stubborness), it's no problem. 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; }
- schlupa 6y agoand *((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