News for hackers. Stuff that matters.
Re:On the history and justification of the C programming lan... by agentultra on Thursday August 18, 2016 @12:22PM (#12313828)
... as if all development of C stopped with the first ANSI standard?

C99 and C11 are great languages. VLAs, anonymous structs, variable initializers, atomics... they're not the C of the 80s and 90s. They still have the usual warts but the tooling is great and support is coming along for the newest features to most platforms.

While the spirit of, "trust the programmer," might have been a historical accident there is some merit for its usefulness. Our chief problem as programmers is managing data: taking some source inputs, performing a transformation, and sending the output somewhere. That's true of video games, web applications, embedded sensors, etc. As a high-level language, C is one of the few that gives the programmer some control over how memory is mapped to the target platform and allows them to build the appropriate abstractions on that hardware.

It's also a loaded weapon... humans make mistakes and inevitably those mistakes make it into our programs. When working in a language like C one must conduct ones self accordingly.

I'm a fan of FP and ML-style languages. I'm looking forward to a day when we can have our cake and eat it too. It'd be nice to be able to define how memory should be handled for a particular application at the granularity of the target platform while still getting the safety guarantees.

I like where Blow is going with his Jai language. It'd be neat to see more research in this area.

Re:On the history and justification of the C programming lan... by pcwalton on Thursday August 18, 2016 @12:37PM (#12314010)
> C99 and C11 are great languages.

I think the amount of undefined behavior in C--and that undefined behavior is necessary to compensate for its design mistakes (e.g. signed overflow)--disqualifies it from being a "great language". Empirically, virtually every single large C program in existence depends on undefined behavior to continue working. And that UB is very difficult to spot [1].

> It'd be nice to be able to define how memory should be handled for a particular application at the granularity of the target platform while still getting the safety guarantees.

> I like where Blow is going with his Jai language. It'd be neat to see more research in this area.

You said that you wanted safety guarantees, but Jai is explicitly not about safety guarantees. In fact, being memory unsafe is one of the key design criteria behind the language. That's what differentiates it from for example Rust.

[1]: https://news.ycombinator.com/item?id=11728324

Re:On the history and justification of the C programming lan... by agentultra on Thursday August 18, 2016 @12:47PM (#12314105)
I don't disagree wrt. UB. I've read somewhere that the reason C is so portable, despite not being designed that way, might be due to "underspecification." Regardless it's something one must be aware of.

As for Jai, etc... right. I was conflating two things. Jai for keeping the spirit of C wrt "the programmer is in control." The other idea being FP languages with hardware-level capabilities.

Re:On the history and justification of the C programming lan... by catnaroek on Thursday August 18, 2016 @01:30PM (#12314564)
> The other idea being FP languages with hardware-level capabilities.

This won't happen until FP implementors work on bridging the gap between typed lambda calculi (ideal source languages) and the C machine model (ideal target machine). This needs:

(0) A limited form of dependent types, tailored to express invariants of data structures, rather than arbitrary mathematical propositions.

(1) Substructural types, so that use-once objects can be reclaimed eagerly and deterministically.

(2) Designing abstractions so that their implementations have no overhead with respect to what a C programmer could have done manually.

But FP people in general don't seem terribly interested in any of these. Instead they write compilers targeting JavaScript.

Re:On the history and justification of the C programming lan... by agentultra on Thursday August 18, 2016 @02:09PM (#12314950)
With my limited experience in Agda I'm really excited about dependent types.

I've been under the impression that there is some research in this area...

Re:On the history and justification of the C programming lan... by catnaroek on Thursday August 18, 2016 @02:35PM (#12315180)
A language whose type level allows you to express arbitrary mathematical propositions can't possibly have as good inference as ML and Haskell have, because higher-order unification is known to be undecidable. Agda and Idris require manual type annotations for all let-bound identifiers. Coq requires all dependent pattern-matching blocks to be type-annotated. This is a real chore, and dependent types will never become mainstream unless their usability improves significantly.

What I have in mind is one way to hopefully achieve that “significant usability improvement”:

(0) Have dependent types, but restrict them to be first-order. This is good enough for programming purposes: invariants of data structures can almost always be expressed as first-order formulas.

(1) Use known and proven type inference technology: generate a system of type-level equations, and solve them via first-order unification, which is known to be decidable and tractable in practice.

But I don't see anyone in the FP community exploring this possibility.

Re:On the history and justification of the C programming lan... by nickpsecurity on Thursday August 18, 2016 @05:20PM (#12316405)
I just got a bunch of papers on first-order verification, implementation, compilers, and so on as the simplicity & tractability part peaked my interest. I'm keeping them in case I run into some students or hobbyists that want to try that on top of some "verify the verifier" kind of issues. Then I see these suggestions...

"(0) Have dependent types, but restrict them to be first-order. This is good enough for programming purposes: invariants of data structures can almost always be expressed as first-order formulas.

(1) Use known and proven type inference technology: generate a system of type-level equations, and solve them via first-order unification, which is known to be decidable and tractable in practice."

I'll add those to the list given that sounds worth a good try. Especially if combined with automated approaches to generating & solving for common attributes like in SPARK and AutoCorres. Maybe something will come of it.

Re:On the history and justification of the C programming lan... by vonmoltke on Thursday August 18, 2016 @12:49PM (#12314124)
> I think the amount of undefined behavior in C--and that undefined behavior is necessary to compensate for its design mistakes (e.g. signed overflow)--disqualifies it from being a "great language".

The undefined behavior is there primarily to account for the variation in platforms. Higher-level languages avoid this by hiding it in a platform-specific compiler or VM, which in turn limits the number of platforms the code can actually be run on.

> Empirically, virtually every single large C program in existence depends on undefined behavior to continue working.

Citation needed. I get that undefined behavior is hard to spot, but having spent years writing cross-platform C I cannot accept that every large program depends on it without some evidence.

Re:On the history and justification of the C programming lan... by pcwalton on Thursday August 18, 2016 @01:19PM (#12314446)
> The undefined behavior is there primarily to account for the variation in platforms. Higher-level languages avoid this by hiding it in a platform-specific compiler or VM, which in turn limits the number of platforms the code can actually be run on.

It may have started this way in the committee (though that isn't true for e.g. type based alias rules), but nowadays it's depended on for performance. You lose a lot of ability to reason about loop trip count if signed overflow is defined, for example.

> Citation needed. I get that undefined behavior is hard to spot, but having spent years writing cross-platform C I cannot accept that every large program depends on it without some evidence.

The probability that a program depends on any of (nonexhaustive list) (a) inspecting the value of a dangling pointer; (b) taking the offset from NULL; (c) type-punning through a union; (d) type-punning through any type other than char; (e) signed overflow; (f) order of operations between sequence points quickly approaches 1.

Here's a very interesting survey investigating this: https://www.cl.cam.ac.uk/~pes20/cerberus/notes50-survey-disc...

Re:On the history and justification of the C programming lan... by vonmoltke on Thursday August 18, 2016 @01:44PM (#12314706)
> It may have started this way in the committee (though that isn't true for e.g. type based alias rules), but nowadays it's depended on for performance. You lose a lot of ability to reason about loop trip count if signed overflow is defined, for example.

I agree it is depended on in many cases, and should not be. That is on the programmers though, not the language designers. The behavior does not exist to cover deficiencies in the language but those of its users.

> The probability that a program depends on any of (nonexhaustive list) (a) inspecting the value of a dangling pointer; (b) taking the offset from NULL; (c) type-punning through a union; (d) type-punning through any type other than char; (e) signed overflow; (f) order of operations between sequence points quickly approaches 1.

Just on your short list I can tell you the probably of any of our C code depending on that approached zero:

> inspecting the value of a dangling pointer

Our code was malloc once, free never. Dangling pointers were by definition impossible.

> taking the offset from NULL > type-punning through a union > type-punning through any type other than char > signed overflow > order of operations between sequence points

Our coding standards covered all of those, so their existence would be a code review failure.

We weren't specifically writing to MISRA C, but I will wager that your statement is not accurate for any project that follows it or any similar standard. Yes, it is a lot of work that you don't need to do with a more controlled and less flexible language. I'm not going to challenge that. I'm just challenging the idea that nobody is writing C that avoids undefined behavior.

Re:On the history and justification of the C programming lan... by catnaroek on Thursday August 18, 2016 @01:52PM (#12314764)
> Our code was malloc once, free never. Dangling pointers were by definition impossible.

Dangling pointers can arise in other ways: use an uninitialized pointer variable, take the wrong offset from an otherwise valid pointer, etc.

Re:On the history and justification of the C programming lan... by vonmoltke on Thursday August 18, 2016 @02:09PM (#12314951)
Those are indeterminate values but they aren't dangling pointers. Dangling pointers are specifically references to an object that has been freed.

Plus, the cases you highlighted are programming errors, not reliance on undefined behavior.

Re:On the history and justification of the C programming lan... by hawski on Friday August 19, 2016 @06:07AM (#12319005)
(a) how program can depend on inspecting the value of a dangling pointer? I can't think of it as not a bug.

(b) True. I think this one should be defined and standardized.

(c) It seems that C99 defined this behaviour. https://stackoverflow.com/questions/11639947/is-type-punning...

(d) I am not knowledgeable enough. Could you give an example?

Re:On the history and justification of the C programming lan... by catnaroek on Thursday August 18, 2016 @12:58PM (#12314201)
> The undefined behavior is there primarily to account for the variation in platforms.

Honest question: Doesn't implementation-defined behavior suffice to address variations across platforms? Undefined behavior has far more drastic consequences: compilers are allowed to assume it simply won't happen.

Re:On the history and justification of the C programming lan... by vonmoltke on Thursday August 18, 2016 @01:22PM (#12314476)
On further review, I think I was conflating undefined behavior with implementation-defined behavior. As pcwalton pointed out, though, in the early days there wasn't really a distinction between the two.
Re:On the history and justification of the C programming lan... by stcredzero on Thursday August 18, 2016 @02:15PM (#12315005)
Higher-level languages avoid this by hiding it in a platform-specific compiler or VM, which in turn limits the number of platforms the code can actually be run on.

False. Squeak Smalltalk runs with a bit-identical model on a ridiculous number of platforms. (which is to say OS/ISA combinations) Though to be fair, it accomplished this trick by having the VM written in a Smalltalk subset that gets translated into C, which is then compiled by local compilers.

Re:On the history and justification of the C programming lan... by nkurz on Friday August 19, 2016 @10:45AM (#12320347)
Citation needed. I get that undefined behavior is hard to spot, but having spent years writing cross-platform C I cannot accept that every large program depends on it without some evidence.

I'm not finding an academic citation, but perhaps a respected academic's blog counts? I think John Regehr is the likely source of these claims. In his words:

  My guess is that most or all executions of GCC
  and LLVM (and basically all other large programs)
  would be undefined.  
http://blog.regehr.org/archives/761

He starts the post by stating that the "majority of the programs in SPEC CINT 2006 execute undefined behavior during the course of a 'reportable' run". A majority is definitely not "all", but the SPEC programs are also not "large":

Let’s consider the SPEC benchmark programs. Making them fast is something that most compiler vendors would like to do. Using IOC we found that a majority of the programs in SPEC CINT 2006 execute undefined behavior during the course of a “reportable” run.

For large programs, he then looks at the GCC and Clang compilers themselves, and concludes:

If we consider them to be written in C99, LLVM/Clang 3.1 and GCC (SVN head from July 14 2012), running on Linux on x86-64, do not appear to admit any non-trivial, non-erroneous executions. I expect the same is true of most or all previous versions of these compilers. IOC tells us that these compilers execute undefined behaviors even when compiling an empty C or C++ program with optimizations turned off.

Lest you think that the undefined behavior is caused by inappropriately forcing C99 on earlier code, he goes on to explain that the problems probably exist there too, but that the lack of tooling for earlier dialects prevents proper analysis:

My guess is that most or all executions of GCC and LLVM (and basically all other large programs) would be undefined by C89 (and not just C99) but we can’t tell for sure without using a comprehensive undefined behavior checker for C89. This tool does not exist. I confess to not personally having the gumption necessary for cramming GCC or LLVM through the best available dynamic undefined behavior checkers: KCC and Frama-C.

His overall message (which I think is true and merits significant reflection) is that C's utility as a real world language is based on unspoken agreements with compiler writers to use some degree of judgment and restraint when making optimizations based on undefined behavior. Rather than a standardized language defined by the written specifications, we are dependent on an "undocumented dialect of C where undefined behavior can sometimes be exploited and sometimes not":

This means that a correct C/C++ compiler could generate code that is almost infinitely faster than the code generated by current compilers. The SPEC harness would of course complain that the compiled programs produce the wrong results, but this is actually a bug in the SPEC harness, not a bug in the compilers. If we insist that a compiler turns these SPEC programs into executables that produce the specified results, then we are effectively mandating that this compiler implements a bizarre, undocumented dialect of C where undefined behavior can sometimes be exploited and sometimes not.

http://blog.regehr.org/archives/761

Re:On the history and justification of the C programming lan... by vonmoltke on Thursday August 18, 2016 @12:40PM (#12314028)
> ... as if all development of C stopped with the first ANSI standard?

For a significant portion of C developers and target platforms, it did. On my last program at my previous company I was required to use C89, in 2012, for portability reasons. The justification was political, not technical.

Re:On the history and justification of the C programming lan... by nickpsecurity on Thursday August 18, 2016 @05:16PM (#12316384)
"... as if all development of C stopped with the first ANSI standard?"

The purpose of the text was to trace why the specific problems in C exist. Its proponents claimed all sorts of justifications and design tradeoffs. After digging through source papers, I found most of these were myths with two, real justifications: hardware constraints & personal preferences. What happened latter on in C didn't matter as core problems were due to the EDSAC, PDP-7, and PDP-11 hardware constraints plus personal tradeoffs of authors. The point is that (a) it wasn't actually designed that way for a good reason (just chopped due to constraints), (b) the possibly good justifications for chopping safety/maintenance no longer applied with better hardware, and (c) people should stop repeating misinformation that there was some grander reason they were there so we can adapt language to new constraints. We might get more improvements on C itself or alternatives as more C users understand there is no grand reason behind the root causes of problems: only due to constraints on hardware you can't buy any more.

"They still have the usual warts but the tooling is great and support is coming along for the newest features to most platforms."

C is bad at the foundation. Alternatives, esp variants on Wirth's stuff, was better within a decade or so. By then, people should be building on better foundations & improving C's. Some even did but little uptake over inertia & backward compatibility. Social & economic thing, not technical.

"As a high-level language, C is one of the few that gives the programmer some control over how memory is mapped to the target platform and allows them to build the appropriate abstractions on that hardware."

There's been safer alternatives that could do that at various points. I'll consider including them in a future version.

" humans make mistakes and inevitably those mistakes make it into our programs. When working in a language like C one must conduct ones self accordingly."

This is sort of a strawman that C proponents critically depend on. C makes many common operations unsafe by default where alternatives, esp like Modula-2, make it safer by default with ability to go UNSAFE if performance or low-level absolutely depend on it with that contained in a module. The reason these problems are in C language by default is nobody changed them. The reason they entered the language early on are the people who invented that philosophy & tech in BCPL had an EDSAC, next had a PDP-7, next had a PDP-11, and none of the three tried a safe subset of ALGOL like Hansen & Wirth did. Both of those built on PDP-11's. Hardware constraints, personal preferences, and not caring about safety/maintenance. That's it.

Once you know this, there's no reason on modern hardware to do a clean-slate project in C if usable alternatives exist. Then someone mentions libraries or compilers. Many safe languages do a strong FFI for C or can compile to equivalent C code. So you still don't need C's problems at level you work with. Then someone mentions talent availability for C. The funny thing about that is that there's very little talent that can write robust, C apps esp under pressure of management to ship fast and including poorly-documented, 3rd-party libs. Only good counter-argument I've seen for using C was, ironically, in safety-critical from a NASA guy pointing out their people with years of C coding using a C subset w/ C testing rigs and four, static analyzers were collectively better bet than clean-slate language w/ less tooling on a project where absolutely everything has to be right. That was true but not the typical situation. ;)

"It'd be nice to be able to define how memory should be handled for a particular application at the granularity of the target platform while still getting the safety guarantees."

Stuff like that already exists and non-experts rewrote ext2 filesystem in it successfully:

https://ts.data61.csiro.au/projects/TS/cogent.pml

Currently using C as the output language given (a) compiler advantage as above and (b) they have the tooling to formally check it via that organizations' work on seL4 project. The part that verifies C is actually a simpler, formally-speced language/framework called Simpl that they embed C into. Myreen et al can go from specs to machine code directly with verified translation, which seL4 used IIRC. So, COGENT could probably go right to machine code via those without C at all. Outputing C is just very practical given their constraints and goals.

I've always suggested modifying PreScheme to do what you said, though. It was a low-level, efficient Scheme meant as a C alternative which outputed C to leverage compilers & optimizations. It and Scheme48 were mathematically verified for correctness in VLISP project. One could add Oberon, SPARK or Rust style checks to PreScheme with ability to turn them off. Basic ones wouldn't be a lot of work at all given it's so small.

https://en.wikipedia.org/wiki/PreScheme

You might also find Habit interesting. It was designed by those behind the House operating system, a Haskell OS. They were designing a new language, Habit, that did things like bit control. They got poached onto a better project IIRC but published a bit on Habit:

http://hasp.cs.pdx.edu/habit-report-Nov2010.pdf

So, there's you three, different approaches to the problem with functional/safe bent.

Re:On the history and justification of the C programming lan... by hga on Thursday August 18, 2016 @05:59PM (#12316632)
Myreen et al can go from specs to machine code directly with verified translation, which seL4 used IIRC.

His special method is to meet in the middle, to analyze the binary code and "turn it into logic" and then check that against the higher level spec. Or something to that effect.

They tried CompCert but there was evidently too great an impedance mismatch. Good thing, too, since CompCert isn't free for most uses.

Re:On the history and justification of the C programming lan... by nickpsecurity on Thursday August 18, 2016 @08:02PM (#12317136)
Basically. The good news is CompCert might not be needed. Remember that seL4 bypassed need for CompCert by somehow translating it directly to ASM. I found out they used Myreen et al's method.

https://www.cl.cam.ac.uk/~mom22/stacks.html

Their work is mindblowing. There's almost no TCB left lol. I still want diverse verifiers in diverse logics and machine codes to verify the HOL checkers and such. I don't trust their verify it in itself sort of method. Not entirely. They do have a nice projects page for CakeML listing each improvement that would be useful and skill estimate. More should do that.

Look at NICTA's COGENT, too. It's open-source now with an ext2 implementation partly or mostly done.

https://ts.data61.csiro.au/projects/TS/cogent.pml

Here's the Simpl language I referenced that's I believe at the heart of AutoCorres tool. They embedded C in it but it's not C specific.

https://www.isa-afp.org/entries/Simpl.shtml

Re:On the history and justification of the C programming lan... by agentultra on Thursday August 18, 2016 @08:04PM (#12317149)
Thanks for this amazing reply. If only you, catnaroek, and I were able to sit down over coffee for an hour or two.

This has been a fascinating thread.

Re:On the history and justification of the C programming lan... by nickpsecurity on Thursday August 18, 2016 @08:39PM (#12317269)
That would be fun. The thread has been more interesting than I thought it would be. Probably thanks to Tomte changing the title haha. We'll all have to have that coffee sometime.