Live data from Hacker News

The Problem with Friendly C

blog.regehr.org

131–140 of 174 posts

Re: The Problem with Friendly C

#131
post #70
post #27

Tone: I do not mean this as sarcasm or merely chasing fashion, I'm quite serious. As both theory and practice are showing, you're never going to be able to get the consensus you want out of C. There's no "saving" C... not because that's somehow mathematically impossible, but simply because the project is too staggeringly large for us to even wrap our heads around. It would literally be easier to get people to start u…

I'll take the bet that in 2035 it's still going to be C/C++ (or a C derivative like Boring C). Because rewriting all that code is an economic impossibility. There's a very long way to go before the rate of foundational Rust code written exceeds the rate of foundational C/C++ code written. And even if you manage to have 100% Rust and 0% C/C++ code being written, you still have a huge legacy to write, which literally c…

'Honestly I think your view of technological adoption is fairly naive -- I don't see much content here other than "everyone get behind Rust!".'

I think you may not have seen much content because you weren't looking for it very hard; for one thing, you seem to have simply instantiated for me an instance of the fallacy I mentioned. People overestimate change in the short term, but underestimate it in the long term.

"IMO the more realistic approach is a systems approach: make it so that badly written C code doesn't completely hose your system."

We've been doing that for 40 years. Since it is already a sufficient problem that C can hose the process it is in, even perfect process isolation is not sufficient. Building all the protection code in C also has a track record of demonstrated failure. You're basically proposing we continue doing the exact same things that are also the reason we're having this conversation in the first place. If this plan worked, we would not even be here.

I'd also point out that if we're talking track records, capabilities have failed pretty comprehensively to date.

"We know (or should know) all this stuff."

And yet, here we are. Theory says this ought to work. Reality says it isn't. Reality wins.

"Another thing the Rust community should be working on is easy and efficient IPC with C programs. So you can rewrite a secure core in Rust and communicate with legacy C/C++ running in an untrusted OS context."

More evidence that you "didn't see much content" in my post because you weren't looking for it is that I already said that.

Finally, I'm arguing the first derivative and you're arguing the zeroth. I think it's perfectly feasible that much more of the code written in 2035 will be in Rust than in C, and people will look at you funny if you insist on writing a new subsystem in C. If you think that's unthinkable, well, that's the long-term underestimating fallacy I was talking about. Since, as I already mentioned in my post, Mozilla is already starting to do this it's hardly unthinkable that by 2035 everybody will be.

With respect, you clearly read what you pre-judged and expected to read in my post, not what I actually said. If you found that to be "naive", well, I don't think that comes from me.

Re: The Problem with Friendly C

#132
post #98

Earlier quoted context omitted.

I love the ideas behind Rust. I don't think it can replace C for all use-cases. C has the use-case of zero-dynamic-allocations. AFAIK, Rust is not very compatible with that mode of use.

Huh? If you don't want any dynamic allocation (or any other features that require support from a runtime system), you can use `#![no_std]` and instead use `libcore` directly. This is how the standard library itself is implemented.

The problem, as I understand it, is that Rust's ownership semantics don't accommodate for the kinds of programming needed by 0 dynamic allocations.

Lots of intrusive nodes pointing freely at one another, is an example. I've heard some Rust libraries approximate intrusive allocations almost perfectly, but not quite perfect.

Re: The Problem with Friendly C

#133
post #98

Earlier quoted context omitted.

I love the ideas behind Rust. I don't think it can replace C for all use-cases. C has the use-case of zero-dynamic-allocations. AFAIK, Rust is not very compatible with that mode of use.

As far as I know, C and Rust give you the same opportunities to work with stack-allocated values.

It's not just stack allocations, it's support for intrusive allocations, pointers not always conforming to simple ownership semantics, etc.

Re: The Problem with Friendly C

#134
post #61

Since, according to Chandler Carruth, the aim for Clang is to not do optimizations based on undefined behaviour without a corresponding instrument in ubsan[0], I don't see much traction on this well-defined/boring C effort. You know, in my experience, things would be great if people actually turned on warnings. I write all my new code with -Weverything with a few noise categories turned off. Everybody should build co…

> Everybody should build code at this level from day 1.

On the project I run, the CI will reject your code in CR if it doesn't compile under two different compilers with all but a handful of warnings turned on as errors, runs and passes tests, and passes various linters, including a check for undocumented types, variables, parameters and return values. IMNSHO, every project should be like this. Once it's setup, it's a breeze and doesn't impede development speed at all.

Re: The Problem with Friendly C

#135
post #132

Earlier quoted context omitted.

Huh? If you don't want any dynamic allocation (or any other features that require support from a runtime system), you can use `#![no_std]` and instead use `libcore` directly. This is how the standard library itself is implemented.

The problem, as I understand it, is that Rust's ownership semantics don't accommodate for the kinds of programming needed by 0 dynamic allocations. Lots of intrusive nodes pointing freely at one another, is an example. I've heard some Rust libraries approximate intrusive allocations almost perfectly, but not quite perfect.

As long as you're willing to use unsafe, you can write things exactly as you can as in C. That's of course, not as satisfying as not needing to, but by encapsulating that in a library and providing a safe interface, downstream users still get the benefits.

Re: The Problem with Friendly C

#136
post #129
post #70

Earlier quoted context omitted.

I'll take the bet that in 2035 it's still going to be C/C++ (or a C derivative like Boring C). Because rewriting all that code is an economic impossibility. There's a very long way to go before the rate of foundational Rust code written exceeds the rate of foundational C/C++ code written. And even if you manage to have 100% Rust and 0% C/C++ code being written, you still have a huge legacy to write, which literally c…

I haven't used it yet, but apparently Rust's FFI with C (in both directions) is quite good: https://doc.rust-lang.org/book/ffi.html

In fact, we removed language features in order to gain a zero-cost interop.

Re: The Problem with Friendly C

#137
post #108

Earlier quoted context omitted.

> I don't believe C should be a language where the compiler does all sorts of high-level optimisation; it should be a straightforward "do what I say" type of language where you get almost exactly what you write, and the only optimisations should be at the level of things like instruction selection --- the optimisations that a programmer would not be able to do at the source level. In that case, you're asking for easi…

What I want is for the semantics of the language to match the semantics of the physical machine I'm writing software for. If on x86 INT_MAX+1==INT_MIN, then that's what should happen on x86. If on ARM INT_MAX+1==INT_MAX, that's what should happen on ARM. No, I don't want portability. Portability means you're coding against the least common denominator. If I want it to be portable, I'll use a different compiler.

> If on x86 INT_MAX+1==INT_MIN [...]

There is no such thing as "+ on x86". "+" is an operator of the C language. Modern x86 has about two dozen instructions that can be used to perform additions, each with slightly different behaviour, and with different performance characteristics. Someone has to define how C's "+" maps to those instructions. That is what the C standard does. The way it does that is by specifying properties that any implementation of C's "+" needs to have, leaving the specific choice of instructions to the compiler writer.

Re: The Problem with Friendly C

#138

Earlier quoted context omitted.

I think the problem is that some of these optimizations aren't just compiler makers being greedy, they're actually a huge benefit. IMO what's missing is the ability to mark areas "unsafe" -- IE, tell the compiler "it's ok to take advantage of certain optimizations here" while marking other areas "please don't goof with this" (ie, security critical code). You can kind of do this with pragmas, but not really. Here's a…

For example, knowing that INT_MAX+1 is undefined allows optimizing "X+1 > X" to "true". If a programmer writes "X+1 > X", chances are this is an overflow check. Doing this is perfectly defined by the standard if X is an unsigned integer, but not if it's signed. That's what doesn't make sense, since they could've made the unsigned case undefined as well. which allows a broad range of loop optimizations to kick in What…

> Doing this is perfectly defined by the standard if X is an unsigned integer, but not if it's signed. That's what doesn't make sense, since they could've made the unsigned case undefined as well.

It does make sense if you understand the historical context: There was a time when some processors still used ones-complement representation for signed integers. That's why the highest performance choice of instructions for signed integer addition would give different results in the overflow case on different processors. Which is why the standard leaves the behaviour undefined, so that compiler writers can choose the instructions that make for the fastest signed addition on the respective target, while programmers can not rely on any specific behaviour.

None of that applies for unsigned integers, and also, the common overflow behaviour of unsigned integers is commonly used intentionally for many types of computations (such as in cryptography), so it is both useful and it doesn't cost anything in terms of performance to define the semantics of unsigned overflow.

Re: The Problem with Friendly C

#139
post #110

Earlier quoted context omitted.

RISC created a huge local minimum by speeding up C code to the exclusion of other languages. I predict that eventually future processors will hide more features from the higher software levels (such as number of registers, instruction types and formats) in order to improve efficiency at the machine level. I think we are seeing this trend with GPUs already. Current CPUs don't do this because they have to maintain bina…

> RISC created a huge local minimum by speeding up C code to the exclusion of other languages Would you mind expanding this.

In the future I believe you are going to see less emphasis on the aggressive speedup of C code for traditional CPUs. Instead you will see many more gadgets with simpler processors that run C code slower in the effort to save power. GPGPUs and algorithm specific hardware (e.g. video, crypto, network, DSP, neural nets) will fill out the rest of the chip. At some point GPUs will have enough raw power and GP features for it to be possible to run an instance of a late-80's operating system within the working set of a single GPU processing element (perhaps with virtual memory emulated as in jslinux.) At that point the need for a power hungry CPU and artificial CPU/GPU distinction will start to fade away completely. Along with Peak Oil we will have Peak CPU.

So, in general I am saying that the road to better performance will not be in aggressive compiler optimization, but rather in higher level design tools to manage totally new software/hardware abstractions. Binaries will be specified at a higher level and look more like source code. At this point my crystal ball becomes admittedly a bit fuzzy.

Re: The Problem with Friendly C

#140
post #52
post #48

Earlier quoted context omitted.

You missed the point of the analogy: It's not about how compilers treat the expression 0/0, but how mathematicians do. If that expression turns up in your calculation, you did something you were not supposed to do and have no one else to blame.

No, rebutting that was exactly my point: programming is, in some ways, a friendlier version of working on mathematical proofs, in that the compiler will tell you when you "did something you were not supposed to do." Programmers expect to be able to hack away like monkeys on typewriters, and just run into a virtual wall whenever they misstep. Compilers will error out when a programmer explicitly types "0/0", and that'…

You are still missing the point. Yes, compilers obviously should not intentionally produce unnecessarily destructive behaviour. But that is not what is happening. What if the code contains "x/y"? Now, the compiler can try to prove that x and y can never be 0 at the same time. But what if that proof doesn't succeed? Maybe x is user input, so who knows what the user will enter at runtime? Now, the language spec could specify that the computation of 0/0 always results in a runtime error. But if it did that, there might be target architectures where the code that would need to be generated to check for that case would have a 300% performance overhead versus code that does unpredictable stuff when it gets fed 0 for both x and y, but in every other case performs a perfectly predictable division. That slowdown would be inacceptable for computation-intensive code where a 0/0 could never happen by construction, even though the compiler can't prove it. And that is why the standard simply says "it's undefined behaviour".
Post reply on HN