C is fun - there's elegance in writing good C code and the mental model you need to understand it is much simpler than the higher level languages.
It's also fun to write data-structures yourself instead of being a mere user all the time. In C you can tell yourself that your take on how to do datastructures is worthwhile and unique (might be a slight stretch) but in other languages almost anything you can do is redundant.
I used to write loads of C, and recently I came back to write some C bindings to a Rust library, and it was _not_ fun. It was dead simple from the C side - mostly just a few functions that constructed or handled opaque pointers. The problem is the error handling is atrocious, and that was so hard to present neatly. The consequence is an overly verbose API in which I've essentially manually monomorphised in C every result. For sure, it's not idiomatic C, but it is properly handling errors, which arguably is one of the main failures of idiomatic C.
It's not just the API either. So once you've got your "nice" error handling API, you have to manually handle resource clean up - no branches that exit for you; every function call is accompanied by a result check and a goto to cleanup code (so your pointers need to be defined properly prior to any calls and initialised to null). Honestly, I don't know I ever lived with this mess. It was a painful and laborious experience to get to something that was just about ok.
> So once you've got your "nice" error handling API, you have to manually handle resource clean up - no branches that exit for you; every function call is accompanied by a result check and a goto to cleanup code (so your pointers need to be defined properly prior to any calls and initialised to null).
I have a stack allocator that will release everything allocated in the function on exit, and I have macros to replace my use of the return keyword that also deallocate everything in the stack allocator before returning.
So my code actually has code cleanup on return.
C does not have to be laborious. Maybe the fact that I have done things like that is part of why I like C?
Where can I can get such a stack cleanup system? Also, can you call arbitrary clean up code (this is hardware that needs cleaning up as well as structures allocated in rust that need to freed in rust)?
I use a stack allocator that knows about setjmp()/longjmp(), functions, scopes, and destructors. (Destructors are a function pointer type in my code.)
Basically, you tell the stack allocator to store a jmp_buf, then you setjmp() on it. Then keep going.
For a function, a special destructor is used as a marker. Same with scopes.
The same is also true of a setjmp() destructor, which is actually what activates longjmp().
The stack allocator should have three functions to unwind itself until it reaches the end of the next scope, function, or jmp, respectively.
Then, when you need an exception, or to exit a function or scope, you call the correct stack allocator function to clean up everything to that point. Then you return or whatever.
This can run arbitrary code on cleanup for an item if you write a "destructor" with that arbitrary code. For example, one idea I had was to use the stack allocator to ensure a mutex or other lock was always released. This would be done by storing a pointer to the mutex and writing a "destructor" that unlocks the mutex when given a pointer to the mutex. Boom. Scope-based mutex unlocking.
I think people use the word "simple" to mean different things. You mean "easy to do," while other people mean "easy to understand what's happening." C lovers love the second definition of simple.
“C lovers” love the appearance of understanding what happens. At the end of the day they still feed their programs to awe inspiring optimizing compilers. Sure, they can probably explain what any snippet of code in their program does, but they can’t tell what, if anything, from that snippet is executed by the machine.
You only need to know, by heart, _a_ list (even a subset) of the documented behaviour of C, you can simply refer to the standard whenever you happen upon something not in your list of known good (or known undefined) behaviour. It's entirely possible to, assuming you can keep this up honestly, write perfectly well defined C without hitting undefined behaviour. It is equivalent to writing brainfuck in a language which is a strict superset of brainfuck. As long as you pick a turing complete subset of C to know the semantics of off by heart, you can write perfectly safe C (the only obstacle being human fallibility). The idea that you need to learn all the documented undefined behaviours in C is a myth and is, in fact, fundamentally wrong on the basis that the documented undefined behaviours in the C standard are only an infinitesimal subset of the set of undefined behaviours in C given that anything not explicitly defined by the C standard is automatically undefined.
If you have a mine-field with an uncountable number of mines, knowing the locations of 200 mines won't help you cross the mine-field safely. If, instead, you learn how to spot areas which are known to be safe, you can, assuming you don't make a mistake, at least attempt to cross it safely (and if you fail to cross it, you can go back and learn how to spot other areas which are known to be safe).
That is the difference between your claim that you need to know all the documented instances of UB and my claim that you just need to know enough defined behaviour to write your program.
It has nothing to do with security assessments or pentests.
Yes, like enjoying wood work == stockholm syndrome, why not go to Ikea??
Also to gp, title perfectly matches, pointing out why he believes in memory safety when using C, everytime also pointing out the flaws with his thinking, and why this only applies to him in his completely owned projects. Not sure what's wrong with the critics here.
> "The next reason is that during my time with C, I have developed a custom software stack designed around memory safety."
Oh ok then. Again goes to show how C is deficient in some areas
I get something being fun, but C ends up needing to worry about a lot of details where you could be actually improving the code in other languages