80 comments

[ 5.2 ms ] story [ 83.0 ms ] thread
What I take from this: computer languages (C++ especially, but also systems built in C) are too complex for the average mind

No, I'm not significantly smarter than the average programmer

That's what needs to be addressed.

While C++ facilitates things, it is complex. While C is very simple it makes mistakes easier by requiring things to be done manually

IDEs don't help. Code completion is helpful but it is of limited help

And we keep repeating ourselves every time we write a for loop

Switch to Common Lisp.

And with lisp, you don't have to repeat yourself: any pattern, or any boilerplate can be abstracted away with a macro.

> can be abstracted away

Except for too many levels of abstraction.

Yes, I believe one of the problems is the way things are abstracted, and I don't see a language solving this

Adding more levels can only go so far

But I don't know how to do it better. Module/Class/Method won't cut it anymore

That's kind of what some compiler optimizations do isn't it? Look through the abstraction and discard it?
The fact that something can be done doesn't mean that it should be done.
How can CL prevent something like "i1 == i1" instead of "i1 == i2" error?
First, since the AST is so simple to walk programmatically, one could write a simple check for that kind of bug in, I'm guessing, a few lines of Lisp.

Second, just because you can come up with a bug that can be written in a language doesn't mean the language doesn't prevent all sorts of other bugs.

All languages can have bugs written in them. That's not the point.

>computer languages (C++ especially, but also systems built in C) are too complex for the average mind

I'm not necessarily disagreeing, but have you looked at the source code [1] of the Apollo Guidance computer [2]? This software was shipped to production 50 years ago. It literally implements a "self-driving space rocket." It is staggering that this was completed in such a short time and actually worked.

The code is written entirely in the "Apollo Guidance Computer (AGC) Assembly" language. The hardware that it was written for had to be invented in at the same time, and was the world's first computer to use Integrated Circuits ("chips"). They also implemented a Real-Time Operating System with a multi-task priority scheduler, as well as a virtual machine and assembly interpreter within the software.

This was mission and life safety critical code, the risk involved boggles the mind. And yet the software was incredibly reliable. It was so reliable that it even saved the Apollo 11 crew and mission during the lunar descent by famously recovering from a peripheral hardware bug.

I honestly do not know how this feat was even humanly possible, but I do know that these programmers did not rely on "code completion."

[1] https://github.com/chrislgarry/Apollo-11 [2] https://en.wikipedia.org/wiki/Apollo_Guidance_Computer

Yeah, sure. But if they'd had code completion it would have been a help, not a hindrance.
>I honestly do not know how this feat was even humanly possible

The Apollo program, fixed for inflation, was something like $130 billion dollars. That's buys you a lot of talent, testing, etc. Its also worth noting that the program wasn't without its screw ups. The Apollo 1 deaths. The radar control on Apollo 11 eating up all the CPU during lunar landing. Apollo 13's famous O2 tank explosion.

I think you may be glamorizing something that was well done, but falls within the realm of 'you get what you pay for' and the occasional human error, which in the case of Apollo 1, turned out to be fatal. I wouldn't call a program with three deaths and an aborted lunar insert to be infallible.

That said, NASA/JPL publish code standards, although I imagine most tech companies would balk at giving up their toys and hot languages/frameworks to do fairly tedious work like this.

http://lars-lab.jpl.nasa.gov/

>That said, NASA/JPL publish code standards, although I imagine most tech companies would balk at giving up their toys and hot languages/frameworks to do fairly tedious work like this.

For most companies developing non-critical software, applying such harsh coding standards will not be cost effective after all. The cost of you browser crashing is not nearly as high as the cost of a crashing rocket...

Besides, even NASA sometimes makes mistakes: http://www.viva64.com/en/b/0416/

Agreed, there are reasons why we do certain things a certain way. But in the age of ransomware and endless cyberwars and nation state spoofing maybe the idea that browsers and other internet facing applications should be barely-shippable shit code is antiquated.
You can't protect everything, but I'm sure they have a secure browser at NSA )
NSA just uses isolation approach in air gaps or hypervisors like these:

The high-assurance community in academia and commercial sectors keep building secure browsers, though. One, OP browser, was inspiration for Chrome security model. They severely weakened it for performance. IBOS is probably most interesting. There's links at the comment below.

https://news.ycombinator.com/item?id=9969961

Quark kernel is one that's not in that comment for some reason:

http://goto.ucsd.edu/quark/

I just realized I forgot the link with their hypervisors. It doesn't matter because most of them suck. You're better off not seeing it. :)
I'm sure that there is a happy medium to be found; a modicum of organisation and discipline must surely save more money by avoiding confusion and wasted time than it costs. How much effort does it take to use a linter? To crank the compiler warnings up to maximum? -- versus the time wasted bug hunting and in heroic struggles with spaghetti-monster codebases...
> The Apollo program fixed for inflation is something like $130 billion. That's buys you a lot of talent, testing, etc.

$130 billion was the total Apollo program budget. For the Apollo Guidance Computer (AGC) software in question, "In total, software development on the project comprised 1400 person-years of effort, with a peak workforce of 350 people." [1]

I would value 1400 programmer person-years at about $200 million. So ... a lot of money, but still less than GitHub's $250 million Series B raise.

Edit: Also, refer to the Mythical Man-Month for explanation of why throwing people and money at a software project doesn't guarantee success.

> Apollo 1 deaths

This was not due to any AGC software bugs. It was a cabin fire during a launch rehearsal test at Cape Canevaral and was essentially a plumbing design issue. [2]

> Apollo 11 eating up all the CPU during lunar landing

That was not catastrophic and was NOT due to an AGC software bug. It was caused by a peripheral hardware error. In fact AGC software's priority scheduler design actually saved the Apollo 11 mission and crew by recovering the CPU. [3]

> Apollo 13's famous O2 tank explosion

Again, nothing to do with the AGC software. Apollo 13 was a mechanical failure related to the famous O-ring issue. [4]

[1] https://en.wikipedia.org/wiki/Apollo_Guidance_Computer#Softw... [2] https://en.wikipedia.org/wiki/Apollo_1#Major_causes_of_accid... [3] https://en.wikipedia.org/wiki/Apollo_Guidance_Computer#PGNCS... [4] https://en.wikipedia.org/wiki/Space_Shuttle_Challenger_disas...

The cost vs results obtained where astronomical and ridiculous. Ok for such pioneering work hitting many grand challenges at once. Not in any way applicable to normal software development given its constraints. However, I think a few numbers from high and medium assurance are interesting to show how things improved.

1. The high-assurance LOCK program to build secure HW/SW system w/ UNIX compatibility layer cost only 58% more than a normal, solid development. That's with ancient formal methods.

2. Altran/Praxis uses strong requirements gathering, formal specs in Z, language-level safety with Ada, design-by-contract for interfaces, SPARK where possible to prove absence of specific errors, and plenty of testing. Error rate is around 0.04 per Kloc. Cost about 50% extra the one time I heard a price reference.

3. seL4 spent about $350/loc on a 10,000 loc system for formal verification down to C itself.

4. COGENT is one of approaches moving safety into type system of safe, system language with certified translators. This allowed non-experts to safe-code the ext2 file system with effort going down from 1.65 person-months per 100 loc in seL4 to 0.69 in COGENT.

So, we're steadily seeing the level and pervasiveness of assurance go up in these projects while cost goes down. Also, as in 80's and 90's recommendations, the best results come from applying high-assurance engineering to stuff that is small, changes little, aids correctness of other stuff, and is reusable. Fortunately, some of our most important stuff has those properties. Including compilers, type systems, parser generators, TLS-style protocols, standard libraries, and so on.

So, we certainly can't spend Apollo money on a pile of assembly code using rope memory getting Apollo results. We can spend 30-50 percent on improvements to software development using existing tools to get nearly 0.04 defects per kloc. We can also do better than Apollo using state-of-the-art tooling like Isabelle/HOL, COGENT, QuickCheck, Design-by-Contract, SPARK, and CakeML. Each thing we build, if focusing on right places, can bootstrap more trust or quality into the other stuff. So, given existing and open-sourced work, it's just as exiting time to be in high-assurance engineering as it was back when Hamilton et al had free reign to invent it.

[1] https://cryptosmith.files.wordpress.com/2014/10/lock-eff-acm...

[2] http://www.anthonyhall.org/c_by_c_secure_system.pdf

[3] https://www.semanticscholar.org/paper/From-a-Verified-Kernel...

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

Margaret Hamilton, whose team built it & co-invented software engineering, described the process they used to build that in "Apollo Beginnings:"

http://htius.com/Articles/r12ham.pdf

It had little to do with assembly language. They did what most don't by trying to understand root cause of every issue they encountered in software development. Then, they modified their tooling and methodology to systematically eliminate it. They also designed a multi-process, fail-safe OS whose properties are similar to Erlang. They also invented a form of Design-by-Contract to catch errors at interfaces, which are majority.

By the time assembly was ready, they had done an amazing amount of specification, analysis, and testing on both individual functions and groups of them. They also had fail-safe and recovery built-in to everything to anticipate inevitable failures, which did show up. There were also 400, highly-motivated individuals working at it for a good chunk of time. The result was this pile of software [1] got people to the moon safely despite multiple failures outside of it. Quite amazing but says almost nothing about safety assembly in regular development.

[1] https://www.wired.com/wp-content/uploads/2015/09/Margaret_Ha...

This also includes analysis of C#, which is quite different from C.
Yes, while C#/Java will prevent some kind of errors from happening, others are very common

(Example: copy/paste errors, parameter order problems, etc)

> While C is very simple it makes mistakes easier by requiring things to be done manually

I wouldn't describe C as simple but basic. Of course, it's start being less basic with all the macros and all the tools needed to compile and distribute a C program , like autoconf ... with all these layers , C becomes as complicated as any other language because it relies on so many 3rd party tools (which are often dynamic languages) to fix its shortcomings. But as long as linux kernel is written in C the language isn't going anywhere.

I wouldn't say that the number of errors in code directly depends on complexity of the language. From my practice I learned that the code quality depends on a software development process implemented in your team. Now we have whole bunch of practices and tools that allow us to minimize risks of appearing stupid mistakes in code: covering the code with unit and integration tests, static and dynamic code analysis, continuous integration, code reviews, refactoring and so on, and, I should say, these things work. So, I think, this article demonstrates that still there are a lot of teams whose development process can be improved.
That's actually the problem Ada's designers set out to solve. They add to what they solve every iteration with safe defaults and contraints on use. Whether you do Ada or not, you will likely find skimming this book to be helpful to see how one can systematically analyze all forms of programmer error and attempt to eliminate them:

http://www.adacore.com/uploads/technical-papers/SafeSecureAd...

That's at language level. At process level, Harlan Mills developed Cleanroom back in 80's to try to get software defects as low as cleanrooms CPU's were built in. It combines a formal approach of describing/connecting things, constrained implementation for easy verification, iterative development, and usage-based testing. Defect rate was extremely low even for first use by teams with cost ranging from slightly more to cheaper due to less debugging.

http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.88....

On productivity side, the DSL-based approach on top of safe, functional languages seems to be winning out. Safe, functional combo already knocks out a lot of problems. DSL's for common categories of programming let you read and write less code to get same work done possibly safer with sane auto-generation (eg parsers, protocols, GUI's). iMatix even did it for C-based, enterprise software.

So, there's certainly work on methods for mainstream software development of average coders with still high quality. Cleanroom was most successful in terms of defect rate. Eiffel pretty much made a market out of it by combining safer language, safe concurrency, OOP, and Design-by-Contract. They're still going strong. Haskell community probably most advanced given last item on my list with some financial companies using it. Jane Street's and Esterel's Ocaml work shows it has similar benefits. These have steeper learning curve but benefits add up quickly afterward.

Cleanroom w/ Design-by-Contract and safe, high-level language seems to be best combo to deal with your list.

Many of the errors are just coding irregularities. Half are really good catches; but half are of the 'lint' sort. Still worth reviewing in case an actual mistake was made.
Right, and so I've developed the view that the most interesting quality of a static analysis tool is not "how many bugs does it find" but "how many of the things it points out are false positives" and (if you want to be really tough) "how many of the things it points out are likely to cause problems for a real user or be actually exploitable by an attacker". Most software projects already have a huge list of bugs they haven't fixed yet, so a tool that identifies 10 easy to fix real bugs is great, but a tool that mixes those 10 real bugs in with a hundred false positives is much less useful, simply because of the time it takes somebody to sift through the list...
I would say, that in this case, with the 50\50 false positive ratio, it is quite manageable, i.e. for every 2 analyzer messages, there is 1 interesting issue in the source code.
Yes. I initially promoted all kinds of static analysis. These days, I'm firmly convinced the friction aspect means the tool needs to be plug-n-play with almost no false positives. Ideally no false positives at all. That maximizes uptake and knocks out many bugs even if more remain.

Another thing I think advocates need to do with lists of such tools is always mention that each one might see errors another won't. This needs to be a refrain that instantly is in people's minds when they wonder about using such tools. Reason is that many make the mistakes of thinking one tool not finding anything means (a) tools don't find stuff in general or (b) there's nothing to find. That implication is even on SQLlite testing page where they applied Clang's analyzer then implied a weaker tool finding nothing in a good codebase meant static analysis itself had nothing to offer (?!).

(comment deleted)
People shouldn't be writing code at all. A lot of testing and small code corrections should be automated at the very least. We have the iron, lets put it to work.
So who writes the automation, then?
Isn't that like asking "So who builds the assembly lines, then?" way back when?
People shouldn't be writing comments at all…
The automation code will still contain much of the same errors. Besides, all modern IDE's provide multiple options for testing and refactoring (code corrections), but apparently this is not enough. At least this proves static analysis has plenty bugs to find after all of these other tools are applied.
As a side project, I'm actually working on something along those lines.

https://github.com/michaelmelanson/autocoder

My theory is that by reducing the search space enough, it should be possible for a computer to generate source code to pass unit tests. The key is from a blog post by Robert "Uncle Bob" Martin where he describes his 'Transformation priority premise' as a way of doing code kata exercises. I think this gives the basis for an automated code generation by presenting unit tests one at a time, and searching for transformations to make the tests pass (while not breaking any earlier ones of course). I have no idea if it'll be a practical way to write software, but I think it's an interesting problem to solve. I'm currently working through some kata exercises, producing the list of transformations manually, to make sure it has the vocabulary of transformations it needs.

https://github.com/michaelmelanson/autocoder/blob/master/src...

After that I'll add a search algorithm to find the sequence of transformations automatically. Then we'll see if my theory is right! :)

My vision is that this would be incorporated into an IDE such that you as the programmer write the unit tests, and the IDE works in the background to write the corresponding code to pass them.

There is a good body of research around 'Programming by Demonstration' or 'Programming by Example': https://en.wikipedia.org/wiki/Programming_by_demonstration

From my own experience doing some research into it, I found the lack of 'common sense' to be the biggest stumbling block; it is hard to detect if the program you generated is a nonsensical 'catchall' solution.

Incidentally, this led me to the paper with the best ever title: How to Wreck a Nice Beach You Sing Calm Incense http://web.media.mit.edu/~lieber/Publications/Wreck-a-Nice-B...

My hope is that constraining the search space, you'll also solve the 'common sense' problem. I'm constraining it in three ways:

1) The solver tries to make the tests pass one at a time: it finds a solution that passes test 1, then one that passes tests 1 and 2, then one that passes tests 1, 2 and 3, and so on. So the human-written unit test suite guides the solution quite directly.

2) The search algorithm will be fairly shallow, somewhere between 2 and 3 steps probably. If it can't find a way to get from tests n to n+1 then it'll throw its hands up and ask you to insert a new test in the middle to help it.

3) Rather than trying arbitrary AST mutations or something, each step will be chosen from a vocabulary of transformations that move the solution from specific to generic -- things like "turn this constant into a variable" or "turn this if statement into a while loop" or things like that -- with simpler transformations preferred over more complicated ones (see the Uncle Bob blog post I mentioned).

In addition to making it computationally tractable, my hunch is that constraining the search like this will also make the solutions similar to what a human would write.

I don't know what tone the article title is going for. Is it meant to imply that open source software is somehow buggier than closed source? Or simply that they made open source software better by finding these bugs.

If the former, it's worth noting that these are 10,000 bugs that are visible because the software is FOSS. Closed source software uses code analyzers/linters too. I worked on a piece of proprietary software where we had a giant spreadsheet for the several hundred bugs and other minor issues that flawfinder found on our software. Those will never get disclosed to the public.

The tone is the same as always: "buy our product". That's what all viva64 submissions are about.
Do you expect them to say "Don't buy our product"?:)
No but I expect them not to make it look like they just want to help OSS
But they are not even trying. They declare it loud and clear: that's our marketing, but we're happy to help OSS
> I don't know what tone the article title is going for.

Did you really not? Then you have not read enough articles in the viva64 blog. :-)

The tone is always "Static analysis with PVS-Studio is a great way to find bugs in projects and it would be a good way to use PVS-Studio for your projects, too".

Of course this is marketing, that is obvious from the title alone. The open source projects give them a means to post a high numbers of bugs found by their magical product. For a high number they just have to scan more products, they can even decide to omit the projects that didn't trigger much bugs. They can't post the results from paying customers in a marketing stunt like this.

They mention that they let the developers of the open source projects know about the issues they find. I am wondering how much time the developers get to patch up before they post their results.

I will give them the benefit of the doubt and assume its the later and not the former. If someone took a Valgrind substitute for Windows and ran a few game bundles, I would guess that over 90% of them has some kind of detectable bug in them in regard to memory management. Access to uninitiated memory and access to free'ed memory should be detected even if you have no access to the source code.

Out of the 10000 bugs that was mentioned by the article, I wonder how many got rated critical by up stream.

> Closed source software uses code analyzers/linters too.

Some might be surprised just how many don't even do that. Several of the products I've worked on relied solely on bug reports (internal and external). If it compiled and passed QA, it went into the field.

Agree with you. A lot of teams where I worked didn't ever think about testing their code.
I think the message is "regardless of what techniques, tools and analyzers you are using right now, more errors can still be found by applying just another tool".
So first you say you don't know, then you say "if it is this thing that I completely made up then they are wrong".

Well, that is certainly an interesting way to comment on an article.

Now I challenge you to find 10000 software contributors.
You can find tons of tickets from PVS-Studio in many bug-trackers :-).
I just love this one: http://www.viva64.com/en/examples/V504/

  void GlyphComboBox::update(SPFont* spfont)
  {
    if (!spfont) return // <=
  //TODO: figure out why do we need to append("")
  // before clearing items properly...

  //Gtk is refusing to clear the combobox
  //when I comment out this line
    this->append("");
    this->remove_all();
  }
Gee, why do you need the dummy append? It's because you put in so many TODO comments that you concealed the missing semicolon that you otherwise might have found ...

This is arguably not a bug; the developer tested the code, massaged it into working as expected, using what look like well-defined constructs, and documented their surprise at certain aspects of the code, leaving this issue easy to find with a grep for TODO.

On another note, what is surprising here is that they didn't catch it with their compiler. Look, the function returns void. GCC has a diagnostic for this, something like "return with expression in a function returning void". I think that still kicks in even if that expression has void type.

Perhaps the append() also returns void. I've seen this kind of bug uncaught by gcc exactly because of that.
Gcc will not issue diagnostic if you return a "void expression" because doing so is valid in C++.
It could still be a warning, since doing so is dubious in C++ even if it is allowed.
Explains why stile matters.

... if (!spfont)

    return;
...

Just add the CR and all is reveled.

Here are the classes of bugs: http://www.viva64.com/en/examples/

I'm no expert, but it looks like most of these would be caught by the Rust compiler at the time they were typed in.

Yes. That's why they don't like rust: http://www.viva64.com/en/b/0324/
That ... is pretty jarring. Their arguments boil down to:

a) No one wants to use a "minor" language, so it will never get traction

b) It's slow (citation: the Benchmarks Game)

c) Static and dynamic analysis can find anything anyways, so what's the point?

First off, anyone who is seriously citing the Benchmarks Game as to making a definitive declaration of whether a language is slow or fast is intellectually dishonest. It's a game (as its name illustrates), so it reflects more the effort that people put in to try to optimize code rather than a comparison of "idiomatic" code. A case in point: the fastest program in C uses SSE intrinsics for its implementation.

Given that they're selling a static analyzer, I would expect them to make the case for analysis. However, it's worth addressing the limitations. Almost no project has 100% test coverage, and even having test coverage isn't necessarily a cure for having no problems (IOC still found undefined overflows in SQLite, which is the only open source project I know of to have 100% line and branch coverage in their test suite). To my knowledge, there still exists no tools that can identify strict-aliasing violations or ODR violations. It's also worth minding Dijkstra's aphorism: testing cannot prove the absence of bugs, only their presence. Static analysis in C/C++ has to face the additional problem of the inability to write a precise pointer analysis--something that Rust's type-safety would fix.

> First off, anyone who is seriously citing the Benchmarks Game as to making a definitive declaration of whether a language is slow or fast is intellectually dishonest.

But Rust is actually significantly slower than C++, that's for sure. You're welcome to test it by yourself.

  >  You're welcome to test it by yourself.
If this is true, please file bugs. They're treated as such.
A Rust k-nucleotide program based on std::collections::hash_map would be welcome.

Edit (2017-02-09):

Here are Rust k-nucleotide programs -

http://benchmarksgame.alioth.debian.org/u64q/program.php?tes...

http://benchmarksgame.alioth.debian.org/u64q/program.php?tes...

http://benchmarksgame.alioth.debian.org/u64q/program.php?tes...

I don't know the history here, but

https://github.com/TeXitoi/benchmarksgame-rs/blob/master/src...

https://github.com/TeXitoi/benchmarksgame-rs/issues/34 (though some things have changed since these comments...)

k_nucleotide.rs implements it's own hash table, and that is no longer accepted: k-nucleotide programs that do that have been removed.

Hence --

    k-nucleotide
	
    source 	secs 	KB 	gz 	cpu 	cpu load
  	    No program 	contribute your program
http://benchmarksgame.alioth.debian.org/u64q/rust.html
What about languages that do not include their own hash tables? C is allowed to, but Rust is not?
No, the C programs are not allowed to implement their own hash table -- and as a consequence no C k-nucleotide program was shown for a couple of months.

http://benchmarksgame.alioth.debian.org/u64q/knucleotide-des...

Rust std::collections provides hash table implementations, it's just a matter of using them.

  > some use a third-party hash table library.
This is what I'm getting at. Since C doesn't provide a built-in hash table, they get to choose one that's good on this benchmark, but other languages can't. That's not great.

(I actually have no idea if the std::collections hashmap is deficient in some way, I care about this in the abstract, not specifically.)

No, they don't "get to choose one that's good on this benchmark".

They get to use a third-party library that was not invented for this benchmark -- that would be the point!

In other news: people who do things in their spare time often make mistakes and do slipshod work.
You clearly haven't worked in a commercial closed source setting.
Projects like Chromium and ChakraCore are not being written in anyone's "spare time." It would be nice if people would stop conflating Open Source with unpaid hobby work. The projects analyzed in this story represent billions in paid labor.
In other news: people who have to focus on detail oriented tasks often make mistakes.

Happy now? Sheesh.

people who have to focus on detail oriented tasks often make mistakes

Whether they're paid well or not.