4 ms·
Why is C not memory safe? It's because you can create things and forget to destroy them, destroy things that are already destroyed, or trust an inaccurate wrray
by gravypod 8y ago
Why is C not memory safe? It's because you can create things and forget to destroy them, destroy things that are already destroyed, or trust an inaccurate wrray length.
If you never do anything of those your program is anecdotally memory safe. Turn all things into libraries (strings, basic data structures, etc) and verify those closely and your C is now what many people call "memory safe". Add valgrind on that and you're pretty safe.
Good patterns and good tooling can combat any issues you have with C if you need to use C. Otherwise just use one of the "!C" languages out there
Other good things:
- Every warning is an error until you can explain to me why that code can't be rewritten any other way
- All code is compiled with -pedantic
- preprocessor hacks should be replaced with inline static functions
- const everywhere
- gnode 8y agoI don't think this really answers the question. While you can be careful with C, it's still inherently dangerous, as you're relying on nothing more than your own human scrutiny to not fuck up. A memory safe language should make this impossible.
- dvfjsdhgfv 8y ago> If you never do anything of those your program is anecdotally memory safe At the same time your C becomes a very special variant of C. When you use the constructs from the SEI CERT C Coding Standard, a lot of things becomes much more complicated than usual. You are more careful, but at the same time spend more time writing code. And even if you do all that, of course you can never be sure about third-party libraries. At some point I just gave up and switched to D, with no regrets.
- gravypod 8y agoExactly. C isn't the right tools for every job. It is the right tools for some but that doesn't mean you should be affraid to look for alternatives.
- reacharavindh 8y agoTrue that there is a safe way of writing C, if I followed x guidelines, and did Y checks. But, I cannot in good conscience trust all the libraries and tools I import have gone through the same diligence. Another thing is, even the basic constructs of the language (for simpler needs like the ones I described in original question)are deemed unsafe - like string processing. Someone told me in passing that I should use Redis's SDS[1] if I want safe strings in C. Do not use char * and manipulate them. I admit that I haven't spent my time understanding why that is the case, or have validated whether it is mitigated magically by using SDS. The point is the need for doing such things for basic elements of a language - strings. What I wonder is why there isn't a language that is C, with safe defaults, easy-to use syntax, as fast as C, and consequentially less powerful. I was hoping Rust was it, until I started to feel scared just looking at the code. At the risk of prejudice, I feel it is more of a glorious C++ than a language I could use for simple general purpose programs(that are still as fast as C). [1] - https://github.com/antirez/sds https://github.com/antirez/sds EDIT : Grammar and reference
- bigato 8y ago> What I wonder is why there isn't a language that is C, with safe defaults, easy-to use syntax, as fast as C Because part of the speed of C is due to the fact that it doesn't do much for you. The moment you want the language to guarantee your memory safety, you'll have to pay either via speed penalty or via added complexity. At least this has been the case with the languages I know. Maybe someday something else will emerge which proves me wrong.
- gnode 8y ago> I was hoping Rust was it, until I started to feel scared I recommend you stick with it. Your understanding of it will improve with practise. Memory safety isn't free -- there's either a language complexity (borrow checking), a runtime complexity (garbage), or a programming complexity (avoiding making mistakes). While there's no one correct option, there is in my opinion a wrong one. Human minds are fallible.
- gravypod 8y agoFunnily enough I was considering including sds as an example in my intial post. The misconception that people have is that C has data structures provided. C is a language of only primatives. There are pointers and there are different width numeric types and structures comprised of those numeric/pointer types. Nothing else is provided by default. No strings, no lists, nothing. For many situations operating at this level of abstraction is ok. Many programs do not ever need a string type. Unfortunately in situations where strings were needed initially the people at Bell Labs decided to use a pointer to a character and come up with convention for that layout of memory. This means that everything must understand those conventions! This is a dangerous and leaky abstraction. As the more times you implement something the more times you can mess it up. SDS provides a single implementatuon for string manipulation by hiding data within the pointer of the string and type aliasing the original char*. It is abstracted from your initial stucture. If you do this with everything you write, using the type system to your advantage, than most of your issues with C will not be an issue. I know the guy behind redis has many videos on his software. From what I've heard he is a modern day software engineering genius and I'm assuming he will have good examples of how to implement this non-leaky abstraction in his software walkthroughs.
- pjc50 8y agoThere's also the "embedded" style: no memory allocation. Throw away malloc() from your standard library and make all variables static globals. It looks odd and all sorts of things become unreasonably hard (such as networking and text processing), but it does guarantee you don't get heap-related bugs if you don't have a heap.
- gravypod 8y agoBack in the olden times game development studios used to do this. They would pre-estimate the maximum number of everything happening (explosion, ai, ammo, etc) and pre allocate everything. Then allocation and deallocations is just a fifo of spaced pointers built on a block of memory pre laid out in a structure in the binary. If you allocate 2x the memory you need then there's no risk of overflows. It's riskier but it makes all of the code dead simple, extremely fast, and is a good middleground between embedded and normal. You do get large binaries though...
- pjc50 8y agoYes, and if it's zero-initialised it can take up zero space in the binary.
- rco8786 8y agoI’m not sure that “write Safe C code” really answers the question here