Live data from Hacker News

Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

cl.cam.ac.uk

211–220 of 253 posts

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#211

Earlier quoted context omitted.

Oh yeah, you're right. Another thing I've done that will work if you have a lot of strcat(), is make a string struct: ktString { int len; int memlen; char *str; } It keeps track of the string's actual length, and the size of the underlying buffer. Then you can 'override' the various string functions: bool ktStrcat(ktString s1, ktString s2); bool ktSprintf(ktString s1, ...); These functions will take care of buffer-si…

... and end up with silent truncation unless you happen to always remember to use only C library functions with explicit length arguments (and which do not assume NUL-terminated strings). Look, I get that there is a place for C, but string manipulation is absurdly bad and error-prone.

Hi! I can't imagine how you understood what I wrote. I specifically said to not use those C library string functions.

I fully admitted that string manipulation is absurdly bad and error-prone, then built on that by showing a way to make it better. Use ktStrcat() instead of strCat(), then you don't have to worry about truncation. Use ktSprintf() instead of snprintf(), then you don't have to worry about truncation. I wish you had understood.

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#212
post #196
post #189

Earlier quoted context omitted.

> Unique pointers provide no protection against use after free, because you can take a reference to their contents and that reference can become dangling. Yes, it's possible, however references should only ever have local scope so, unless you're dealing with threads or asynchrony it's hard to write sane code where this happens, and if you have those things, and you're passing refs or ptrs, then I don't have to tell y…

> Mentioning free() just implies that you're willing to accept resource leaks to avoid UAF bugs, which is nuts because UAFs can be a lot easier to debug. If you're focused on security, it goes in the opposite direction: a resource leak can lead to a denial of service, but an use-after-free can lead to remote code execution, which is much worse. From that point of view, it's worth it risking a resource leak if by doin…

> then call a method on that temporary which returns a reference to within the temporary

The obvious answer to this would be never to return references to members (or anything tied to the objects lifefime), but if you really must then you can always use a qualifier to prevent this pattern from compiling.

https://ideone.com/UuZYJe

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#213
post #178

Earlier quoted context omitted.

It's unusual to take references to the contents of a unique pointer. There is one idiom which says that if one has a smart ptr and a function taking a ref, the raw ptr should be passed, but that's it. It's frowned upon... nay scoffed at to store references one receives as parameters, so that temporary ref will go away after the function call, leaving the smart ptr as unique owner. This should not be a problem and it…

> It's unusual to take references to the contents of a unique pointer. No, it's not. It happens every time you call a method on the referent (well, OK, this is technically not a reference, but it doesn't matter to the argument).

If you're calling a method on the object referred to by a unique_ptr, then you won't have a use-after-free because the thing will exist. The only way it wouldn't exist would be if you typed "delete myuniquePtr.get()", which would be dumb.

It could be a null unique_ptr of course, but I don't see how this is anything worse than a denial-of-service.

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#214
post #7

This is another article overanalyzing the success of C, when in fact the reason for the success of C is very simple and obvious: Unix was free and in a lucky position in 1973; Unix got popular; C is the language of Unix; therefore C got popular. There is no inherent benefit in C that, for example, a somewhat modified version of Pascal or Algol wouldn't have inherited. And these kinds of articles always ignore the fac…

I've used both C and Pascal in embedded systems. Pascal is painful compared to C. A "somewhat modified" version might help, but I doubt it would be enough. To steal a phrase from my friend Michael Pavlinch: Pascal was like picking your nose with boxing gloves on. A modified boxing glove isn't really going to solve the problem. For that matter, once we weren't on Unix but rather on the PC, and we had a nicely-modified…

> Pascal in embedded systems

aka Modula-2

http://cms.edn.com/ContentEETimes/Documents/ESC%20Proceeding...

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#215
post #181

Earlier quoted context omitted.

> Even such a simple use case is fraught with major problems: > > 1. who allocates needed memory? > > 2. who free's it? That's also a major feature. It allows people to write systems that are resilient in the face of tight memory limitations. It's not cool when a language forces string operations to allocate & duplicate memory willy-nilly. > 3. can the compiler constant fold cat("hello","world") ? Does the result win…

It's the opposite. I've seen lots of code written in C that pretends to be out of memory safe. I've never once seen such a program that actually is out of memory safe. Invariably the codepaths triggered by malloc returning null are never exercised. With a GC and exceptions you can theoretically be quite resistant to OOM conditions, not that anyone really cares.

Very, very few C programs can handle running out of disk space. This includes the operating system(s). Get close to filling up the disk, and try various things.

Just recently, I was having a lot of trouble with Windows Update hanging. I finally noticed that free disk space was low. Freed up more space, and WU started working again.

For fun, try:

    #include 
    int main() { printf("hello world\n"); return 0; }
and redirect stdout to a file on a device that is full. Amazingly, it succeeds!

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#216
post #186

Earlier quoted context omitted.

I used snprintf(), too, but it is only a minor improvement. Problematic in C is something as simple as concatenating strings: Mystring s,t; t = "hello"; t = cat(s,s); t = cat(s,s,s); t = cat("hello",s); t = cat(s,"world"); t = cat("hello","world"); Even such a simple use case is fraught with major problems: 1. who allocates needed memory? 2. who free's it? 3. can the compiler constant fold cat("hello","world") ? Does…

Here's roughly what that would look like using Bernstein's C string library (which was not only used in qmail). #include "stralloc.h" ... static stralloc s, t; ... if (!stralloc_ready(&s, 0)) die_nomem(); if (!stralloc_copys(&t, "hello")) die_nomem(); if (!stralloc_copy(&t, &s)) die_nomem(); if (!stralloc_cat(&t, &s)) die_nomem(); if (!stralloc_copy(&t, &s)) die_nomem(); if (!stralloc_cat(&t, &s)) die_nomem(); if (!s…

Yes, that does work. But it's not without problems, not the least of which it's just not attractive to look at. For example, concatenating "hello" and "world" allocates memory, when it should instead give you a "helloworld" string literal. In fact, simply initializing `s` with a string literal needlessly allocates memory, and that's anti-ethical to performance. Calling die_nomem() leaks memory if it does anything but terminate the program. All those tests for memory exhaustion are tedious.

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#217
post #213

Earlier quoted context omitted.

> It's unusual to take references to the contents of a unique pointer. No, it's not. It happens every time you call a method on the referent (well, OK, this is technically not a reference, but it doesn't matter to the argument).

If you're calling a method on the object referred to by a unique_ptr, then you won't have a use-after-free because the thing will exist. The only way it wouldn't exist would be if you typed "delete myuniquePtr.get()", which would be dumb. It could be a null unique_ptr of course, but I don't see how this is anything worse than a denial-of-service.

No, you could get a reference to the container of the object and indirectly delete it. For example, if the unique pointer were part of a global std::vector, clearing the vector would invalidate the this pointer.

Keep in mind that you are at this point arguing against the existence of actual zero-days that have occurred in Firefox (and lots of other software). This is not a theoretical concern.

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#218
post #113

Earlier quoted context omitted.

C's popularity is due to the fact that it is predictable within certain bounds (single thread or limited concurrency). No GC pauses, no weird runtime crashes due to a strange constructor, no gigantic exception chains, etc. The only languages in the TIOBE index that can even try to make that claim are: C at #2, C++(if you subset it) at #3, Objective-C/Swift(#18/#11), Assembly at #14, Ada at #29, and maybe FORTRAN(#35)…

Isn't this a circular argument: C is popular because no other language on the top popularity chart does . There are many languages with the these properties and better safety, but they aren't popular like C.

Really? I'd love their names. I'm not being snarky here.

I'd love to have a nice language alternative to C.

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#219
post #113

Earlier quoted context omitted.

C's popularity is due to the fact that it is predictable within certain bounds (single thread or limited concurrency). No GC pauses, no weird runtime crashes due to a strange constructor, no gigantic exception chains, etc. The only languages in the TIOBE index that can even try to make that claim are: C at #2, C++(if you subset it) at #3, Objective-C/Swift(#18/#11), Assembly at #14, Ada at #29, and maybe FORTRAN(#35)…

The idea that C is predictable is in my view a sign of someone who hasn't got to know C really well. The trends around undefined behaviour will hopefully put a bullet in the head of this idea for good. It's extremely hard to look at C and reason about what an optimising compiler will turn it into. Malloc is not more predictable than a GC pause. Both malloc and free can take unpredictable amounts of time. If anything…

> The trends around undefined behaviour will hopefully put a bullet in the head of this idea for good. It's extremely hard to look at C and reason about what an optimising compiler will turn it into.

Sure when you turn on -Oinfinity. Nobody does that in embedded unless they are hard pressed on some metric (RAM size, generally, or CPU flops occasionally).

Overall, though, C is really fairly predictable. Unsigned arithmetic does what you expect--the fact that signed arithmetic doesn't under higher optimizations is a fairly recent phenomenon (and not an uncontroversial one). Variables go where you expect. Pointers act like you expect. Casting and precedence sometimes sneak up on you, but parentheses generally manage that.

Const has issues at the boundary cases. Trying to stuff something into ROM and then telling the rest of the system that "really-no-you-cant-cast-that" can make things tricky with "incompatible pointer" issues.

Floating point arithmetic, though, is just a disaster.

> Malloc is not more predictable than a GC pause.

Ayup. And what's the first thing real-time embedded folks do? Throw out malloc (which is library, not language, but that's pedantic). Real-time-embedded systems tend to allocate all memory statically, up-front. Or they use a custom malloc that they control the behavior of.

> C not having exceptions doesn't make it more predictable. It just means that if something goes wrong you get a useless and probably corrupted core dump.

Predictable and useful are orthogonal.

And, the fact that I can't attach to running state of a crashed program is a failure of TOOLS not the language. The fact that I can't attach to a system that crashed, examine the state, fix what I need to, and continue is a fault of the people who make C IDE's. There is no reason other than lack of monetary incentive that this cannot be done.

Re: Some Were Meant for C: The Endurance of an Unmanageable Language [pdf]

#220
post #144
post #113

Earlier quoted context omitted.

C's popularity is due to the fact that it is predictable within certain bounds (single thread or limited concurrency). No GC pauses, no weird runtime crashes due to a strange constructor, no gigantic exception chains, etc. The only languages in the TIOBE index that can even try to make that claim are: C at #2, C++(if you subset it) at #3, Objective-C/Swift(#18/#11), Assembly at #14, Ada at #29, and maybe FORTRAN(#35)…

The fact that there are these other languages with the same properties means that predictability isn't the real reason, right? It's that it also is sparse in its specification and easy to implement a compiler for.

Please name those languages. I'm serious.
Post reply on HN