Live data from Hacker News

Love C, hate C: Web framework memory problems

alew.is

61–70 of 218 posts

Re: Love C, hate C: Web framework memory problems

#61
post #13
post #4

Earlier quoted context omitted.

> What is interesting is that the apparent cleanliness of the code (it reads very well) is obscuring the fact that the quality is actually quite low. I think this is a general feature and one of the greatest advantages of C. It's simple, and it reads well. Modern C++ and Rust are just horrible to look at.

The safer the C code, the more horrible it starts looking though... e.g. my_func(char msg[static 1])

I don't understand why people think this is safer, it's the complete opposite.

With that `char msg[static 1]` you're telling the compiler that `msg` can't possibly be NULL, which means it will optimize away any NULL check you put in the function. But it will still happily call it with a pointer that could be NULL, with no warnings whatsoever.

The end result is that with an "unsafe" `char *msg`, you can at least handle the case of `msg` being NULL. With the "safe" `char msg[static 1]` there's nothing you can do -- if you receive NULL, you're screwed, no way of guarding against it.

For a demonstration, see[1]. Both gcc and clang are passed `-Wall -Wextra`. Note that the NULL check is removed in the "safe" version (check the assembly). See also the gcc warning about the "useless" NULL check ("'nonnull' argument 'p' compared to NULL"), and worse, the lack of warnings in clang. And finally, note that neither gcc or clang warn about the call to the "safe" function with a pointer that could be NULL.

[1] https://godbolt.org/z/qz6cYPY73

Re: Love C, hate C: Web framework memory problems

#62
post #6

Earlier quoted context omitted.

I slightly unironically believe that one of the biggest hindrances to rust's growth is that it adopted the :: syntax from C++ rather than just using a single . for namespacing.

I believe that the fanatics in the rust community were the biggest factor. They turned me off what eventually became a decent language. There are some language particulars that were strange choices, but I get that if you want to start over you will try to get it all right this time around. But where the Go authors tried to make the step easy and kept their ego out of it, it feels as if the rust people aimed at creati…

> I believe that the fanatics in the rust community were the biggest factor.

I second this; for a few years it was impossible to have any sort of discussion on various programming places when the topic was C: the conversation would get quickly derailed with accusations of "dinosaur", etc.

Things have gone quiet recently (last three years, though) and there have been much fewer derailments.

Re: Love C, hate C: Web framework memory problems

#63
post #61
post #13

Earlier quoted context omitted.

The safer the C code, the more horrible it starts looking though... e.g. my_func(char msg[static 1])

I don't understand why people think this is safer, it's the complete opposite. With that `char msg[static 1]` you're telling the compiler that `msg` can't possibly be NULL, which means it will optimize away any NULL check you put in the function. But it will still happily call it with a pointer that could be NULL, with no warnings whatsoever. The end result is that with an "unsafe" `char *msg`, you can at least handl…

> I don't understand why people think this is safer, it's the complete opposite.

Yup, and I don't even need to check your godbolt link - I've had this happen to me once. It's the implicit casting that makes it a problem. You cannot even typedef it away as a new type (the casting still happens).

The real solution is to create and use opaque types. In this case, wrapping the `char[1]` in a struct would almost certainly generate compilation errors if any caller passed the wrong thing in the `char[1]` field.

Re: Love C, hate C: Web framework memory problems

#64
post #2

There are many, many more such issues with that code. The person that posted it is new to C and had an AI help them to write the code. That's a recipe for disaster, it means the OP does not actually understand what they wrote. It looks nice but it is full of footguns and even though it is a useful learning exercise it also is a great example of why it is better run battle tested frame works than to inexpertly roll yo…

Yeah, I recently wrote a moderate amount of C code [1] entirely with Gemini and while it was much better than what I initially expected I needed a constant steering to avoid inefficient or less safe code. It needed an extensive fuzzing to get the minimal amount of confidence, which caught at least two serious problems---seriously, it's much better than most C programmers, but still. [1] https://github.com/lifthrasiir…

> It needed an extensive fuzzing to get the minimal amount of confidence, which caught at least two serious problems---seriously, it's much better than most C programmers, but still.

How are you doing your fuzzing? You need either valgrind (or compiler sanitiser flags) in the loop for a decent level of confidence.

Re: Love C, hate C: Web framework memory problems

#66
post #5

> Another interesting choice in this project is to make lengths signed: There are good reasons for this choice in C (and C++) due to broken integer promotion and casting rules. See: "Subscripts and sizes should be signed" (Bjarne Stroustrup) https://open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1428r0... As a nice bonus, it means that ubsan traps on overflow (unsigned overflows just wrap).

Yup, unsigned math is just nasty. Actually, unchecked math on an integer is going to be bad regardless of whether it's signed or unsigned. The difference is that with signed integers, your sanity check is simple and always the same and requires no thought for edge cases: `if(index max)`. Plus ubsan, as mentioned above. My policy is: Always use signed, unless you have a specific reason to use unsigned (such as memory…

> The difference is that with signed integers, your sanity check is simple and always the same and requires no thought for edge cases: `if(index max)`

Wait, what? How is that easier than `if (index > max)`?

Re: Love C, hate C: Web framework memory problems

#67
post #22
post #15

Earlier quoted context omitted.

I meant implicit casting, but I guess that really falls under promotion in most cases where it's relevant here (I'm on a train from Aarhus to Copenhagen right now to catch a flight, and I've slept considerably less than usual, so apologies if I'm making some slight mistakes). The issues really arise when you mix signed/unsigned arithmetic and end up promoting everything to signed unexpectedly. That's usually "okay",…

I prefer C to Zig. IMHO all the successor languages throw out the baby with the bathwater and add unnecessary complexity. But Zig is much better than Rust, but, still, I would never use it for a serious project. The "promoting unexpectedly" is something I do not think happens if you know C well. At least, I can't remember ever having a bug because of this. In most cases the promotion prevents you from having a bug, b…

> Recently I saw somebody "upgrading" a C code basis to C++ and also changing all loop variables to size_t. This caused a bug which he blamed on working on the "legacy C code" he is working on, although the original code was just fine.

I had the same experience about 10 years back when a colleague "upgrade" code from using size_t to `int`; on that platform (ATMEGA or XMEGA, not too sure now) `int` was too small, overflowed and bad stuff happened in the field.

The only takeaway is "don't needlessly change the size and sign of existing integer variables".

Re: Love C, hate C: Web framework memory problems

#68

Earlier quoted context omitted.

I’m sorry, but there is an incredible amount of hard data on this, including the number of CVEs directly attributable to memory safety bugs. This is publicly available information, and we as an industry should take it seriously. I don’t mean to be disrespectful, but this cavalier attitude towards it reads like vaccine skepticism to me. It is not serious. Programming can be inconsequential, but it can also be national…

So what do you propose to do?

I propose that we start taking the appropriate amount of professional responsibility.

That includes being honest about the actual costs of software when you don’t YOLO the details. Zero UB is table stakes now - it didn’t use to be, but we don’t live in that world anymore.

It’s totally fine to use C or whatever language for it, but you are absolutely kidding yourself if you think the cost is less than at least an order of magnitude higher than the equivalent code written in Rust, C#, or any other language that helps you avoid these bugs. Rust even lets you get there at zero performance cost, so we’re down to petty squabbles about syntax or culture - not serious.

Re: Love C, hate C: Web framework memory problems

#69

Earlier quoted context omitted.

Yeah, I recently wrote a moderate amount of C code [1] entirely with Gemini and while it was much better than what I initially expected I needed a constant steering to avoid inefficient or less safe code. It needed an extensive fuzzing to get the minimal amount of confidence, which caught at least two serious problems---seriously, it's much better than most C programmers, but still. [1] https://github.com/lifthrasiir…

> It needed an extensive fuzzing to get the minimal amount of confidence, which caught at least two serious problems---seriously, it's much better than most C programmers, but still. How are you doing your fuzzing? You need either valgrind (or compiler sanitiser flags) in the loop for a decent level of confidence.

The "minimal" amount of confidence, not a decent level of confidence. You are completely right that I need much more to establish anything higher than that.

Re: Love C, hate C: Web framework memory problems

#70

Earlier quoted context omitted.

So what do you propose to do?

I propose that we start taking the appropriate amount of professional responsibility. That includes being honest about the actual costs of software when you don’t YOLO the details. Zero UB is table stakes now - it didn’t use to be, but we don’t live in that world anymore. It’s totally fine to use C or whatever language for it, but you are absolutely kidding yourself if you think the cost is less than at least an orde…

> I propose that we start taking the appropriate amount of professional responsibility.

I agree. For me that means: software engineering should start taking the same attitude to writing software that structural engineers bring to the table when they talk about bridges, buildings and other structures that will have people's lives depending on them. I'm not sure how we're going to make rings out of bits but we need to realize - continuously - that the price of failure is often paid in blood, or in the best case with financial loss and usually not by us. And in turn we should be enabled to impose that same ethic on management, because more often than not that's the root cause of the problem.

> That includes being honest about the actual costs of software when you don’t YOLO the details.

Does that include development cost?

Maintenance costs?

Or just secondary costs?

Why the focus on costs?

> Zero UB is table stakes now - it didn’t use to be, but we don’t live in that world anymore.

This is because 'Rust and C# exist'? Or is it because Java, Erlang, Visual Basic, Lisp etc exist?

> It’s totally fine to use C or whatever language for it, but you are absolutely kidding yourself if you think the cost is less than at least an order of magnitude higher than the equivalent code written in Rust, C#, or any other language that helps you avoid these bugs.

We were talking about responsibility first, and that goes well beyond just measuring 'cost'. The mistake in bringing cost into it is that cost is a business concept that is used to justify picking a particular technology over another. And just like security is an expense that doesn't show anything on the balance sheet if it works besides that it cost money the same goes for picking a programming language eco-system.

So I think focusing on cost is a mistake. That just allows the bookkeeper to make the call and that call will often be the wrong one.

> Rust even lets you get there at zero performance cost, so we’re down to petty squabbles about syntax or culture - not serious.

The debate goes a lot further than that. You have millions of people that are writing software every day that are not familiar with Rust. To get them to pick a managed language over what they are used to is going to take a lot of convincing.

It starts of with ethics, and I don't think it should start off with picking a favorite language. You educate, show by example and you deliver at or below the same cost that those other eco-systems do and then you slowly eat the world because your projects are delivered on-time, with provably lower real world defects and hopefully at a lower cost.

And then I really couldn't care what language was picked, in the rust world that translates into 'anything but C' because that is perceived to be the enemy somehow, which is strange because there are many alternatives to rust that are perfectly suitable, have much higher mind share already.

C is - even today - at 10x the popularity that rust is, it will take a massive amount of resources to switch those people over, and likely it will take more than one generation. In the meantime all of the C code in the world will have to be maintained, which means there is massive job security for people learning C. For people learning rust to the exclusion of learning C that situation is far worse. This needs to be solved.

These are not 'petty squabbles' about syntax or culture. They are the harsh reality of the software development world at large, which has seen massive projects deployed at scale developed with those really bad languages full of undefined behavior (well, that's at least one thing that Assembly Language has going for it, as long as the CPU does what it says in the book undefined behavior doesn't exist). People are going to point at that and say 'good enough'. And they see all those memory overflows, CVEs etc as a given, and they realize that in spite of all of those the main vector for security issues is people, and configuration mistakes not so much the software itself.

This is not ideal, obviously, but C, like any bad habit, is very hard to dislodge if your main argument is 'you should drop this tool because mine is better'. Then you need to show that your tool is better, so much better that it negates the cost to switch. And that's a very tall order, for any programming language, much more so for one that is struggling for adoption in the first place.

Post reply on HN