hn-classics/_stories/2010/7326534.md

1643 lines
94 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
created_at: '2014-03-01T22:57:04.000Z'
title: When you see a Heisenbug in C, change your compiler's optimization level (2010)
url: http://esr.ibiblio.org/?p=1705#
author: adamnemecek
points: 42
story_text: ''
comment_text:
num_comments: 82
story_id:
story_title:
story_url:
parent_id:
created_at_i: 1393714624
_tags:
- story
- author_adamnemecek
- story_7326534
objectID: '7326534'
year: 2010
---
[Source](http://esr.ibiblio.org/?p=1705# "Permalink to When you see a heisenbug in C, suspect your compiler’s optimizer | Armed and Dangerous ")
# When you see a heisenbug in C, suspect your compiler’s optimizer | Armed and Dangerous
# [Armed and Dangerous][1]
## Sex, software, politics, and firearms. Life's simple pleasures…
* * * ### Main menu
[Skip to primary content][2]
[Skip to secondary content][3]
* [Home][4]
Search
### Post navigation
←[ Previous][5] [Next →][6]
# When you see a heisenbug in C, suspect your compilers optimizer
Posted on [2010-02-13][7] by [Eric Raymond][8]
This is an attempt to throw a valuable debugging heuristic into the ether where future Google searches will see it.
Yesterday, my friend and regular A&D commenter Jay Maynard called me about a bug in Hercules, an IBM360 emulator that he maintains. It was segfaulting on interpretation of a particular 360 assembler instruction. But building the emulator with either -g for symbolic debugging or its own internal trace facility enabled made the bug go away.
This is thus a classic example of [heisenbug][9], that goes away when you try to observe or probe it. When he first called, I couldnt think of anything helpful. But there was a tickle in the back of my brain, some insight trying to break into full consciousness, and a few minutes later it succeeded.
I called Jay back and said “Turn off your compilers optimizer”.
Compiler optimizers take the output stream from some compiler stage and transform it to use fewer instructions. They may operate at the level of serialized expression trees, or of a compiler intermediate representation at a slightly later stage, or on the stream of assembler instructions emitted very late (just before assembly and linking). They look for patterns in the output and rewrite them into more economical patterns.
Optimizer pattern rewrites arent supposed to change the behavior of the code in any way other then making it faster and smaller. Unfortunately, proving the correctness of an optimization is excruciatingly difficult and mistakes are easy. Mistaken optimizations that _almost always_ work are, though rare in absolute terms, among the most common compiler bugs.
Optimization bugs have a strong tendency to be heisenbugs. Enabling debugging symbols with -g can change the output stream just enough that the optimizer no longer sees the pattern that triggers the defective rule. So can enabling the conditioned-out code for a trace facility.
When I told Jay this, he reported that Hercules normally builds with -O3, which under GCC is a very aggressive (that is to say somewhat risky) optimization level.
“OK, set your optimizer to -O0,”, I told Jay, “and test. If it fails to segfault, you have an optimizer bug. Walk the optimization level upwards until the bug reproduces, then back off one.”
I knew of this technique because Ive been in this kind of mess myself more than once most recently the code for interpreting IS-GPS-200, the low-level bit-serial protocol used on GPS satellite-to-ground radio links. It was compromised by an optimizer heisenbug that was later fixed in GCC 4.0.
This morning Jay left a message in my voicemail confirming that my diagnosis was correct.
I said above that optimizer bugs have a strong tendency to be heisenbugs. If you are coding with an optimizing compiler, **the reverse implication is also true**, especially of segfault heisenbugs. The _first_ thing to try when you trip over one of these is to turn off your optimizer.
You wont hit this failure case very often — Ive seen it maybe three or four times in nearly thirty years of C programming. But when you do, knowing this heuristic can save you many, _many_ hours of grief.
### Google+
![Eric Raymond][10][ ][11][Eric Raymond][11]
This entry was posted in [Software][12] by [Eric Raymond][13]. Bookmark the [permalink][14].
## 93 thoughts on “When you see a heisenbug in C, suspect your compilers optimizer”
1. ![][15][morgan greywolf][16] on [2010-02-13 at 10:26:57][17] said:
Believe it or not, this happens more often than you think. Back when I had time to sit around and wait for my entire OS to compile (before I got married), I ran Gentoo, in the very early days of the distro. On the forums there (which, at one time, were filled with highly skilled hackers instead of the trolls, complainers and whiners that seem to fill its forums for the last few years), one of the common memes on the Gentoo forums was that if you were experiencing random segfaults or lockups with certain packages, removing or adjust any -O? options from your CFLAGS would fix it, _especially_ if they were set -O3. The common advice of the day was to never do more than -O2 optimization globally, unless you were prepared to deal with problems.
Of course, nowadays, I dont even bother: 64-bit Ubuntu is nice and tightly integrated these days, and everything “just works” out of the box. Kinda takes all the fun out of it. :)
[Reply ↓][18]
2. ![][19][Jay Maynard][20] on [2010-02-13 at 10:29:37][21] said:
As it happens, there are at least two optimizer bugs tickled by the offending (?) code. Building with `-O0` works. Building with `-O1` breaks. Building with `-O1 -fno-guess-branch-probability` works. Building with `-O2 -fno-guess-branch-probability` breaks.
I “solved” the problem by sticking in one trace call that made the problem go away. That kind of fix makes me vaguely nauseous, but ugly working code beats pretty broken code every time.
I should have known this was likely to be the problem. [Hercules][22] has proven to be a stress test for gccs optimizer in the past, and, for the longest time, the Hercules configure script explicitly set its own gcc optimization flags for different architectures to ensure that it didnt trip over any of them.
Eric, a discussion of why optimizers have such a hard time being provably correct might be enlightening to your readers, as well…
[Reply ↓][23]
3. ![][24]Frank Ch. Eigler on [2010-02-13 at 10:55:53][25] said:
For the sake of completeness, one should observe that compiler optimizers can appear to break code when in fact the code makes invalid assumptions, and was therefore a latent bug there rather than in the compiler. It would be illustrative to have Jay explain the particular problem he found in this case.
[Reply ↓][26]
4. ![][27][esr][28] on [2010-02-13 at 11:03:24][29] said:
Im thinking now about writing a web resource called “Stalking the Wild Segfault” on debugging tactics for C programmers. Things to go in there, besides this story:
* Why your intuitions are so often wrong
* Localize, characterize, fix: The three stages of debugging
* Bisection searches, importance of
* On a segault, try gdb first.
Thoughts on other useful topics?
[Reply ↓][30]
5. ![][31]Michael Poole on [2010-02-13 at 11:05:11][32] said:
There are also categories of bugs that show these symptoms but are bugs in the actual code. Less expert programmers are more likely to trip over these than compiler bugs. Given the level of expertise of the analysts here, Im inclined to believe that the compiler-bug diagnosis is correct.
One of my “favorite” cases (which kept me up all night once because it was affecting a 30,000-user IRC network) was a one-byte buffer overrun that exhibited as an infinite loop. When optimization was off, or debug information turned on, the stack ended up being arranged in a way such that the overrun didnt affect the behavior. With -O1 and without -g, there was no padding inserted between variables, and that one-byte overrun reset the counter to zero for a loop that contained the overrun.
Just to be clear, the “less expert programmer” responsible for the bug in that case was me. Now that I have been through that experience, and have more years of programming experience in general, I doubt I would make the same mistake again.
[Reply ↓][33]
6. ![][19][Jay Maynard][20] on [2010-02-13 at 11:07:24][34] said:
Frank, Im not sure what more I can say without posting the (fairly lengthy) section of code that failed. The sufficiently curious can obtain the Hercules source code from the Subversion repository at `svn://svn.hercules-390.org/hercules/trunk`. The failure was in the block beginning at line 4158 (at this writing) of the file `esame.c`.
[Reply ↓][35]
7. ![][19][Jay Maynard][20] on [2010-02-13 at 11:15:02][36] said:
The gdb manpage is about as useful as the gcc manpage. You might want to consider a quick cheat sheet for the debugging options most useful for arrowing in on a bug.
[Reply ↓][37]
8. ![][38]Dan on [2010-02-13 at 11:16:23][39] said:
_Eric, a discussion of why optimizers have such a hard time being provably correct might be enlightening to your readers, as well…_
Actually, the formal proof of such a refinement is not so horrendous…proving the mapping between the formal statement and concrete executable is somewhat more challenging.
Thats why God gave us Z & SPARK Ada ;)
[Reply ↓][40]
9. ![][41][Michael Mol][42] on [2010-02-13 at 11:19:57][43] said:
Had something similar happen just a couple weeks ago. Spent hours and hours trying to figure out what was causing a crash in the field. The crash dumps were proving to be useless, so I turned off optimization of the compilation unit in question, and the bug went away.
However, in our case, it turned out that turning on or off optimizations only exacerbated a race condition. It was a rather amusing case of thinking the problem is the fault of one thing, only to find out its the fault of something else.
Ive seen two compiler optimization bugs in the last three years, verified by looking at a disassembly of the resulting code, but I spend most of my time in C++, which throws a monkey wrench into things all on its own. (More common are template processing bugs that prevent perfectly valid code from compiling in the first place.)
[Reply ↓][44]
10. ![][38]Dan on [2010-02-13 at 11:40:00][45] said:
Of course, I am anally-bound to voice my queasy objection to using compiler optimization…_ever_.
The horrors that cannot be unseen….. ;)
[Reply ↓][46]
11. ![][15][morgan greywolf][16] on [2010-02-13 at 12:26:50][47] said:
> Thoughts on other useful topics?
Tips for finding known and unknown library and/or kernel bugs. I know that that ones bit me in the ass a few times. For instance, I have one network performance benchmarking tool I wrote a long time ago that oddly will segfault on some older Linux kernels, especially with certain NICs, due to a kernel bug that, at the time, seemed to affect only certain network card drivers (the venerable 3COM 3c905b “Boomerang” cards being among them).
[Reply ↓][48]
12. ![][49]TOK on [2010-02-13 at 12:31:20][50] said:
Its not always an optimizer bug even if changing the -O option changes the behaviour.
At work we ran into a situation where our code would crash or not depending on the size of the compiled binary. If the size hit one of a set of certain multiples of 4, it would crash. The root cause was a combination of five “almost always works” bugs in the first-stage bootloader that loaded the next-stage loader over a serial port. Nothing wrong in the compiler, just bugs in our code.
In that case, changing the -O setting would change the binary size, avoiding or triggering the problem randomly.
Dan, completely skipping optimizations *is* completely anal. Thats because the compiler output before any optimizations is completely anal. Of the code generated for a small function, easily 50% of the instructions may be useless — less for longer functions but still way too much. Im talking about dead simple peephole stuff; the less trivial optimizations are well known to cause problems. Id like them to be hidden behind long and clumsy option names so theyd not be used lightly. They have less effect anyway.
[Reply ↓][51]
13. ![][52][John Graham-Cumming][53] on [2010-02-13 at 12:31:28][54] said:
Have you examined the assembly code produced to determine that this is an optimizer bug? If so, Id love to see the detailed explanation. Should be fascinating.
[Reply ↓][55]
14. ![][38]Dan on [2010-02-13 at 12:47:26][56] said:
_Dan, completely skipping optimizations *is* completely anal._
Easy tiger ;) I do plenty of code optimization…I specifically object to *compiler* optimization.
I realize this casts me as a luddite in the eyes of many.
[Reply ↓][57]
15. ![][58]techtech on [2010-02-13 at 12:58:00][59] said:
Frank Ch. Eigler Says:
> compiler optimizers can appear to break code when in fact the code makes invalid assumptions, and was therefore a latent bug there rather than in the compiler.
Agreed, one of the hardest debugging lessons for beginners or non-programmers to understand is:
  **Bugs are not guaranteed to be harmful.**
A bug can hide inside software for years, hurting nothing from the users point of view but still doing something clearly wrong to the program state. Then you come along and make a perfectly reasonable change to the software. But you were assuming the program state your changes depended on was valid, which it wasnt. The software breaks, sometimes in expensive or embarrassing ways, and you are blamed. Frantic, you recheck your changes over and over, but find nothing wrong.
Now everyone not only thinks youre so incompetent that you broke the software, they also believe youre incapable of to fixing your own mistakes. Ah the joys of software development.
[Reply ↓][60]
16. ![][61]Jessica Boxer on [2010-02-13 at 13:29:10][62] said:
Frankly, I think this is bad advice. Compiler bugs are very rare in practice, as you say: you, a heavy user, have a rate of 0.1 per year. People are far better using other debugging techniques to find their bug, including assembly level debugging. Please note the very important point that TOK makes which is that turning off optimization and seeing the bug go away is not a valid solution. It is perfectly possible that the bug is just being hidden, and could readily reappear with a minute change in an apparently unrelated place.
Good developers dont just make bugs go away, they find out what caused the bug, and fix the cause. If the optimizer does have a bug then I would want to debug at the assembly language level to convince myself that the compiler was producing different incompatible code with and without the optimizer before I would accept the claim that “it is a compiler bug.” Preferably, Id like to see a ten line example that exhibited the bug (and then send it to the compiler writer.)
I might add that this is particularly bad advice for newbie programmers, who may use it to blame every unpredictable bug on the compiler.
[Reply ↓][63]
17. ![][19][Jay Maynard][20] on [2010-02-13 at 13:52:19][64] said:
Jessica, I tried looking at the assembler output from the routine in question with and without the trace calls that made the problem go away. The program logic was sufficiently buried that I couldnt make heads or tails of it and there were enough differences in other ways that a direct line-by-line comparison wasnt possible.
I spent a solid week trying to chase down this problem. It was only reported on one platform; the identical test case run on four other platforms did not fail. Combine that with the fact that turning off the optimizer made the code work correctly on the failing platform, and the evidence is overwhelmingly a compiler bug.
[Reply ↓][65]
18. ![][66][David Gerard][67] on [2010-02-13 at 14:14:15][68] said:
+1 to a detailed technical discussion on this stuff. Youve been in the systems programming mines, meta-maps are always useful
(Im a sysadmin, not a programmer. But I deal with enough software that _almost_ builds and/or works that more tricks and tips for the toolbox are _always_ valuable.)
[Reply ↓][69]
19. ![][70]josh reich on [2010-02-13 at 14:18:37][71] said:
If the bug is in GCC, please provide a patch to the source.
Thats what I was always told whenever I suspected the compiler as the source of my heisenbugs. I say my, because every time I tried to locate the actual bug in GCC, the bug would always be in my code.
Have you run valgrind & friends over your code?
[Reply ↓][72]
20. ![][73][William B Swift][74] on [2010-02-13 at 14:35:33][75] said:
>It’s not always an optimizer bug even if changing the -O option changes the behaviour.
But _if the behavior does change_ then there is an optimizer bug, even if the problem youre trying to fix is not caused by said bug. Optimization is not supposed to change the behavior, if the behavior does change, there is a bug there.
[Reply ↓][76]
21. ![][49]TOK on [2010-02-13 at 14:41:53][77] said:
> Easy tiger ;) I do plenty of code optimization…I specifically object to *compiler* optimization.
And thats precisely my point. A human would never write as thoroughly stupid code as what a compiler outputs before any optimizations. Im talking about completely useless instruction sequences.
The thing is, the compilation phase is usually written so that it only thinks about outputting the stuff necessary to, say, begin a function, perform arithmetic on input, and return from a function. Each phase expects certain things in certain registers and leaves things in a place where the next phase will find them. Taken together, this causes tremendously stupid sequences like values being copied from register A to register B for the next phase, which begins by copying B to A. Etcetera.
Trivially simple optimizations are *heavily* needed for compiler-produced code. They are easy to implement without bugs. Complex optimizations may get some cases wrong, they are a different story. But its not at all reasonable to decline *any* optimization on code directly out from the code-generation phase of a typical compiler.
Jays case looks like an optimizer bug, though. Given that a compiler with optimizations on produces broken code from a certain source, most likely the optimization bug depends only on the contents of the function where the bug-triggering source is. Small unrelated changes outside that function do not make the bug appear or disappear. In our case instead, while it at first seemed that adding a simple “if (expression) { do_something(); }” caused our program to crash, we could in fact get that modified function to work perfectly well by adding or removing a few bytes elsewhere to offset the binary size away from a “bad” value. Add another 8 bytes and the bug bit again. So it clearly wasnt the compiler breaking on the source code, but something else that depended on the total size of the binary. For a compiler bug, changes elsewhere dont change things. (This is an oversimplification of course, and subject to complex interactions between a function and its surroundings, but sane developers tend to minimize these interactions.)
Franks point must also be kept in mind. Optimization options also tend to elicit more warnings from the compiler, as the compiler notices during optimization that something is never used or something similar, but optimizations may also reveal bugs in the source by making the program crash instead of printing a warning at compile time.
[Reply ↓][78]
22. ![][58]techtech on [2010-02-13 at 15:06:58][79] said:
William B Swift Says:
February 13th, 2010 at 2:35 pm
> But if the behavior does change then there is an optimizer bug, even if the problem you’re trying to fix is not caused by said bug. Optimization is not supposed to change the behavior, if the behavior does change, there is a bug there.
Not true. An optimizers primary purpose is to change the timing behavior of your program, right? A timing-dependent bug inside the program could easily be triggered by the differences in timings between the unoptimized and optimized versions of the program.
The optimizer is also free to change program behaviors that are supposed to be hidden from the users, but are revealed by a bug in the program. For example, optimization could change the memory layout/initialization order of a programs variables, turning a benign buffer overflow bug in the program into a segfault+core dump.
Contrary to your statement, and contrary to the jist of ESRs blog entry, turning compiler optimizations on and off can easily hide and/or reveal bugs in the program being compiled. I agree with Jessica Boxer; the compiler is generally better-tested than anyones code, so dont blame the optimizer until youve reduced the bug to a very short test case that you know is correct. When in doubt, assume any bug is your own softwares fault.
[Reply ↓][80]
23. ![][15][morgan greywolf][16] on [2010-02-13 at 15:12:01][81] said:
> I might add that this is particularly bad advice for newbie programmers, who may use it to blame every unpredictable bug on the compiler.
Excellent point. 99.999% of the time, its really _not_ a bug in compiler, _especially_ if youre just learning. The popular compilers like gcc are very mature and have been well-tested on thousands of different systems and configurations. True compiler bugs are _far_ more likely to be discovered by a well-seasoned cranky old-man programmer like ESR or Jay Maynard. :)
[Reply ↓][82]
24. ![][15][morgan greywolf][16] on [2010-02-13 at 15:23:01][83] said:
> I spent a solid week trying to chase down this problem. It was only reported on one platform; the identical test case run on four other platforms did not fail. Combine that with the fact that turning off the optimizer made the code work correctly on the failing platform, and the evidence is overwhelmingly a compiler bug.
Another good point is in there: compiler optimization bugs usually dont manifest on every platform or on every version of the compiler. They usually work perfectly on several platforms, with major fail on one, maybe two. Also, if it works perfectly on _your_ platform, but fails on several others, youre probably just not doing things in a cross-platform way; maybe you have an endian problem or youre assuming that an API function youre calling behaves the same way on all platforms. There are very few times in life youre likely to truly encounter an actual compiler bug vs. it being a bug in your own code.
[Reply ↓][84]
25. ![][38]Dan on [2010-02-13 at 15:23:25][85] said:
Lots of generalizations there TOK ;) Needless to say, I dont agree with your observations at all.
Admittedly, my view is shaped by my backgrund in formal methods and the fact that I have been through the wringer while writing my own compiler & VM I have a pretty darned thorough understanding of this aspect of software technology, right down to the metal.
My approach is likely far closer to Jessicas than yours…..or most programmers, I imagine.
[Reply ↓][86]
26. ![][87][John Regehr][88] on [2010-02-13 at 15:42:25][89] said:
Jay the latest gcc gives some fairly alarming warnings when compiling esame.c from hercules 3.06. Its not necessarily correct but these would be worth looking into.
[Reply ↓][90]
27. ![][87][John Regehr][88] on [2010-02-13 at 15:47:11][91] said:
The -O0 people should consider that some versions of gcc (this was in the 2.x days I believe) have more reliably produced correct output at -O1 than -O0, since almost nobody uses -O0.
When debugging embedded software, I find that a moderate degree of compiler optimization is extremely helpful because most of the really stupid instructions have gone away, leaving the core program logic. -O0 from most compilers is very cluttered and hard to read. The single optimization that makes debugging most hellish is function inlining, and its easy to turn that off.
[Reply ↓][92]
28. ![][93][Terry A. Davis][94] on [2010-02-13 at 15:53:17][95] said:
I had a funny compiler bug in my compiler that shocked and scared me because I caught it so late.
I had optimized the CMP instruction with immediate values…
if (x>5) worked
if (5>x) did not work
When I optimized, I negated the logic of the compare.
“(5>x)” is not “!(x>5)” its “!(x>=5)”
I didnt catch it for years because I happen to code my compare instructions consistently.
[Reply ↓][96]
29. ![][19][Jay Maynard][20] on [2010-02-13 at 16:23:05][97] said:
> There are very few times in life you’re likely to truly encounter an actual compiler bug vs. it being a bug in your own code.
In general, this is the case. We tend to trust our tools implicitly. Erics point is that, sometimes, the tools dont live up to that trust.
[Reply ↓][98]
30. ![][99][maht][100] on [2010-02-13 at 17:04:48][101] said:
Gnu is Not Useful
[Reply ↓][102]
31. ![][103]Jake Fischer on [2010-02-13 at 17:15:12][104] said:
Its worse than this.
Weve now reached an age where we have computers with large (>= 4GB) non-ECC memories, and such a machine is essentially guaranteed to have a memory error every three days. <http://lambda-diode.com/opinion/ecc-memory>
Here is an older article by Dan Bernstein which states that computers with as little as 256MB of non-ECC memory will have several memory errors a year. <http://cr.yp.to/hardware/ecc.html>
and Jessica, as you gain more experience with compilers (especially the mound of shit that is gcc) youll find they generate errors (bad code) all the time. Very few of these will cause segfaults though.
Im not aware that esr has done any significant compiler work though.
[Reply ↓][105]
* ![][106][esr][28] on [2010-02-13 at 18:32:27][107] said:
>I’m not aware that esr has done any significant compiler work though.
Ive written a couple of retrocompilers. I cheated by having them compile to C, though, and letting the low-level code generation be someone elses problem.
[Reply ↓][108]
32. ![][109]Smy D on [2010-02-13 at 18:13:04][110] said:
This isnt a bad debugging tool of changing the flags about, but you should really check your expectations because usually it is your fault anyways.
[Reply ↓][111]
33. ![][19][Jay Maynard][20] on [2010-02-13 at 18:17:52][112] said:
John, try grabbing the latest copy from Subversion and see if it still does. 3.06 is, by now, pretty old.
[Reply ↓][113]
34. ![][114]Mike Stewart on [2010-02-13 at 19:27:28][115] said:
>But if the behavior does change then there is an optimizer bug, even if the problem you’re trying to fix is not caused by said bug.
This isnt true the best counter-example is an incorrectly synchronized multi-threaded program. (Hercules appears to be multithreaded.) Compilers can aggressively reorder reads and writes in a way which produces identical behaviour for a single thread of execution, but causes race conditions to occur much more often than they did before.
In addition, values read from main memory may also be re-used for much longer timescales on high optmisation levels. The canonical example is looping while a variable is true, with a different thread falsifying the condition variable at some point, without either thread inserting memory barriers. On an unoptimised build, the looping thread probably executes a read on every iteration, so it will break out; the optimised version reads once, then spins forever.
This is totally legit behaviour on most processors memory models. Its a specific instance of the general issue: if your code has entered the land of undefined behaviour, even if it works, the next optimisation level or update to your compiler could break it.
[Reply ↓][116]
35. ![][38]Dan on [2010-02-13 at 20:03:32][117] said:
Cheater cheater pumpkin eater ;)
Actually, if you can support the constructs of your source language with another, using an established compiler this way is definitely working smarter
Sadly I didnt have that luxury…..and no, I didnt provide any “-O” features.
[Reply ↓][118]
36. ![][119][johnc][120] on [2010-02-13 at 20:04:09][121] said:
Dan,
“I am anally-bound to voice my queasy objection…”
Please, try to keep the discussion non X-rated.
The word you, and 99.999+% of the population meant to use was anile, and yes, it is a “homophone.” ;-)
I suspect that is why so many people get it wrong.
It is a small peeve of mine; please consider this just a small effort to (make like a diode and) rectify the situation.
-John
[Reply ↓][122]
37. ![][123][Sean Conner][124] on [2010-02-13 at 20:04:42][125] said:
A year and a half ago ( <http://boston.conman.org/2007/10/18.1> ) I squashed a heisenbug that wasnt due to a compiler bug, but a race condition in a non-threaded non-multi process program (if you handle signals, you have a multi-threaded program; end of story). It only took me a month to track that down.
In my twenty years of programming professionally, Ive only found one (I think) compiler bug in my time. Either Ive been really lucky, or I havent written enough C code.
[Reply ↓][126]
38. ![][61]Jessica Boxer on [2010-02-13 at 21:05:46][127] said:
# William B Swift Says:
> But if the behavior does change then there is an optimizer bug,
This is incorrect. The compiler is required to preserve the defined behavior, not the undefined behavior. For example:
int i; if(i == 0) seg_fault();
I can think of scenarios where the optimizer would compile this differently than a standard debug build. For example, some debug builds set default values for all local variables, but that code might be omitted (validly so) in an optimized build. (Microsofts compilers have behavior like this — though I didnt test the above code.)
The bug here is in the code, not the compiler. And of course this is in your face, but bury this in fifty lines of code, and make it only occur when some rare path occurs through that code, and youve got yourself a very difficult bug.
Of course a good compiler will issue a warning after the DFA, but plenty of people turn them off, or ignore them, which although a common practice, always struck me as an insanely stupid thing to do.
[Reply ↓][128]
39. ![][19][Jay Maynard][20] on [2010-02-13 at 21:11:55][129] said:
Hercules is very heavily multithreaded, but we do use interlocks to keep accesses to shared structures from stepping on each other. (We use several housekeeping threads, as well as one thread per emulated CPU and some number of threads from 1 to as many I/O devices as are defined, depending on some configuration parameters, to achieve overlapping of I/O and CPU activity in the same way the real iron does.)
When weve had threading issues, though, the problem has manifested itself as unreliable execution and bugs that dont manifest themselves the same way every time. This was not the case this time. The problem was reliably repeatable, and broke at the same place in the emulated program every time in the same way. This doesnt feel like a threading bug.
[Reply ↓][130]
40. ![][131]Brian Hurt on [2010-02-13 at 21:58:55][132] said:
Strongly recommended advice for everyone coding in C:
1) Crank warnings way up- enable all warnings!
2) Fix all warnings.
Almost all “bugs” in the optimizer come from the optimizer having different behaviors for code constructs with undefined behaviors than the non-optimized code has. And C has a lot of undefined behaviors. However, most C compilers these days (including both GCC and Microsoft) have warning settings that will warn you when you use these undefined behaviors. However, most programmers disregard these warnings- and thus leave themselves wide open to depending (silently) on undefined behaviors that can change under different optimizer settings, and will change under different platforms.
It is much easier to fix all the warnings- even the truly unnecessary ones- than it is to track down one of these Heisenbugs.
Especially once you stop coding the warnings into the code in the first place.
Oh, and if you find yourself having to typecast things all over the place, consider whether your variables are the correct type. For example, most loop variables should be of type size_t, not int.
[Reply ↓][133]
41. ![][24]Frank Ch. Eigler on [2010-02-13 at 22:10:24][134] said:
Jay, the suspect section of code is rather pointer-intensive. With alias analysis, it is conceivable that the hercules code is in fact not kosher. OTOH, gcc 4.2 was a bit of a dud release, IIRC. What would help decide one way or another is the (annotated) assembly code for the function, contrasting a working version from a non-working one. If this problem still occurs on modern gcc, it would be very important & helpful to report it in some detail, so the experts can diagnose it and fix gcc (or perhaps suggest how to fix your code, depending…).
[Reply ↓][135]
42. ![][136]Roger Phillips on [2010-02-13 at 22:22:31][137] said:
>I said above that optimizer bugs have a strong tendency to be heisenbugs. If you are coding with an optimizing compiler, the reverse implication is also true, especially of segfault heisenbugs. The first thing to try when you trip over one of these is to turn off your optimizer.
this is bad advice. neither the standard nor common implementation practice give any guarantee that the compiler will always produce the same behavior for the same program. there is, for example, no guarantee regarding the order of execution of expressions in c aside from across sequence points.
[Reply ↓][138]
43. ![][38]Dan on [2010-02-13 at 22:49:03][139] said:
@johnc No, “anile” isnt the word I was looking for, but thanks for teaching me a new word-of-the-day :)
[Reply ↓][140]
44. ![][119][johnc][120] on [2010-02-13 at 23:21:27][141] said:
Agreed Dan, nothing to become anile about ;-)
These usages are simply shibboleths, if you will; practised since the Latin era, at least.
Their point was to discriminate the literati from the mere intelligentsia.
[Reply ↓][142]
45. ![][143]Tom Dickson-Hunt on [2010-02-13 at 23:35:57][144] said:
I have had a compiler bug (well, compiler behavior inconsistency; it was really my fault) only once. This in a toy OS kernel that I wrote for fun; I had some inline asm that referred directly to a certain register while using GCCs give-me-a-register notation as well, and didnt list my directly-used register in the clobberlist. Turned out GCC used the same register for its %0, so it clobbered the value in the register. The tutorial code I got that particular bit from used the same syntax, but something about it was different enough to make GCC use a different register. Moral: Never assume anything, and also compilers are weird.
[Reply ↓][145]
46. ![][146]chuck on [2010-02-14 at 03:04:51][147] said:
We (numpy) ran into a problem where gcc inlined memcpy and optimized it by using the alignment of the passed type even when it was cast to char* in the code. The gcc folks [dont regard this as a bug][148].
[Reply ↓][149]
47. ![][146]chuck on [2010-02-14 at 03:27:00][150] said:
Apropos those who have seldom run into compiler bugs, Ive run into plenty, starting with the MS Pascal compiler that passed doubles down the call stack as singles. Back in the day it was difficult to use a MS compiler more than a week or so without uncovering a bug. A more recent MSVC compiler bug involved the incorrect optimisation of a logical expression that failed when the numbers were nans. I also ran into a hardware bug on the 80186 where it got the wrong sign dividing two negative integers when both were in registers, but did just fine when one was in memory. So on and so forth. That said, things are much improved these days.
[Reply ↓][151]
48. ![][152][Jeff Bonwick][153] on [2010-02-14 at 05:23:46][154] said:
Prime Directive for debugging: take every bug to root cause.
Far too many engineers have no idea what this really means. Knowing root cause means that you can say, with complete specificity, exactly what went wrong and why. Memory location X had this value, register R had that value, then we executed this instruction, etc.
If you change the optimization level and the bug goes away, that does *not* prove that theres a bug in the optimizer. It is far more likely that you have an uninitialized variable and the optimized code just happens to use different registers. To claim that you *know* its an optimizer bug you must be able to disassemble the code, annotate it, and identify the particular instruction does not compute what the source code says it should.
The anatomy of a correct bug fix goes like this:
(1) You determine the root cause of the bug.
(2) You develop a test that can reproduce the bug at will. This can be hard to do, especially with multithreaded code, but if you really know what the root cause is then you should be able to figure out exactly where to insert delays (e.g. right after dropping a relevant lock) to open up the window for race conditions. You may have to build a custom kernel, libraries, etc to help in this task.
(3) You develop a fix, based on your understanding of the root cause.
(4) You can explain *why* your proposed fix should address the root cause.
(5) With the fix applied — and nothing else changed — your test runs indefinitely without hitting the bug.
That is real debugging. Its demanding, but anything less is voodoo.
[Reply ↓][155]
49. ![][156]Bill Moorier on [2010-02-14 at 05:38:49][157] said:
A good discussion of this post can be found on Hacker News: <http://news.ycombinator.com/item?id=1123147>
[Reply ↓][158]
50. ![][19][Jay Maynard][20] on [2010-02-14 at 06:12:43][159] said:
The terminally curious may now download a zip file of the assembler output of compiling the version of esame.c under discussion (also included) with and without the PTT() calls that made the code work and at several different optimization levels. I found the generated assembler nearly impenetrable, but others may not. The file may be obtained at <http://www.hercules-390.org/esamebug.zip> .
[Reply ↓][160]
51. ![][19][Jay Maynard][20] on [2010-02-14 at 06:24:40][161] said:
Oh, a couple more notes: the version of esame.c in the zip file corresponds to revision 5627 of the Subversion repository. (Its unchanged as I write this, but that probably wont last as long as this discussion will.) The function in question is in the generated assembler as z900_load_multiple_long. Each instruction in the emulator may be generated as many as three times, to correspond to the three different architecture modes hercules supports, and the name of the instruction is prefixed with the architecture mode to build the actual routine name that is used.
[Reply ↓][162]
52. ![][19][Jay Maynard][20] on [2010-02-14 at 06:38:35][163] said:
And, Eric, this brings up another topic for your resource: a guide to reading generated assembler. You can assume that your audience knows the assembler in question, but not anything about how gcc generates assembler code or what kids of code it tends to generate.If someone like me can strip away the boilerplate and get to the meat of the generated code, it would make finding this kind of problem simpler.
[Reply ↓][164]
53. ![][15][morgan greywolf][16] on [2010-02-14 at 07:27:33][165] said:
> Back in the day it was difficult to use a MS compiler more than a week or so without uncovering a bug.
Which is why, back in the day, there were those of us using Borlands compilers. All the MS-DOS programs I ever wrote (gak!) were written and compiled using Turbo Pascal. When I started coding on Unix in 1989 (SysVR3.2), I immediately realized that it was a platform created by programmers for programmers. :) When the first Linux distros hit the scene in the mid 90s, I switched platforms and never looked back.
[Reply ↓][166]
54. ![][38]Dan on [2010-02-14 at 08:27:04][167] said:
As the other threads discussion notes a quality toolkit (and the knowledge/discipline to use it) is invaluable.
When I use gcc, it is conjoined with valgrind. “Cleanliness is next to godliness” is a heuristic I put great stock in. Elimination of sloppiness (good housekeeping) really does help in significantly reducing the clutter than can impede bug hunting.
[Reply ↓][168]
55. ![][19][Jay Maynard][20] on [2010-02-14 at 10:22:34][169] said:
For the insanely curious or terminally geeky, theres now a test case at <http://www.hercules-390.org/lmg-test.zip> .
[Reply ↓][170]
56. ![][61]Jessica Boxer on [2010-02-14 at 10:37:45][171] said:
BTW, this discussion reveals a deeper truth: the various changes in modern programming languages are a good idea, because they tend to eliminate these problems. I think, for example, it is very sad what has happened to C++. It was a leader in the language world, but has now become so moribund in the politics of language design, and the limited vision of Stroustrop, that it is absolutely an also rand now. The reality of C++ is illustrated in the fact that the C++0x standard will never in fact be 0x. Not to mention that the changes proposed are anemic. I know a lot of people use it, and that it is probably one of the most widely available languages, but the fact is that its lack of features have made it significantly less productive than more modern languages like Python and C#. Just as one trivial example, it is illegal to use an uninitialized variable in C#, and all the necessary data flow analysis is built into the language itself (if you doubt this consider the difference between a ref parameter and an out parameter.) This eliminates, in one stroke, a significant class of bugs.
[Reply ↓][172]
57. ![][156]Bill Moorier on [2010-02-14 at 13:32:07][173] said:
John Graham-Cumming has a good followup to this post, here: <http://www.jgc.org/blog/2010/02/bad-workman-blames-his-tools.html>
[Reply ↓][174]
58. ![][175]Ivan on [2010-02-14 at 13:35:15][176] said:
I think I found the problem.. And well it appears it is NOT a compiler bug although it exhibits all its characteristics!
(for the enthusiast, the code in question is at labels L2488/L2494 and L2493/L2497 in Jays provided esame.O3 listing).
One of the constraints of the computer architectures the hercules project implements is that under certain conditions, 8 byte aligned fetches & stores must appear atomic to other processors in the configuration.
Unfortunately, under ia32, there is only *ONE* way to do this (besides locking out all architecture memory accesses for all threads) : and that is the “cmpxchg8b” instruction. Since there is no simple way to do this in C, when we are under the auspices of gcc, we make some very light use of the __asm__ construct.
Another thing now comes into play. When compiling PIC (thats Placement Independent Code), the various ia32 ABIs we use (ELF, Mac OSX) mandate that the EBX register is reserved to hold a GOT (Global Offset Table) pointer so it cant be used for other purpose (lest you get gcc complaining VERY loudly !).
Ok.. So on one hand we want to use this cmpxchg8b instruction which make an implicit use of the EBX register but that register is reserved. So the code we implemented takes a detour and before and after the instruction saves the EBX register into another register weve reserved before hand so that the whole unit of operation preserves EBX and makes gcc happy.
And thats where we hit a snag with *this* particular version of the compiler (but it could hit us again any time) : For this particular unit of work, the compiler decided it didnt really need EBX any more after all before it returns to the caller (and restore EBX to its original value) so the EBX register suddenly became free so it decided to use it as part of the __asm__ code for *another* purpose : as a memory pointer for cmpxchg8b BAM ! we clobbered EBX as part of our attempt to protect it so basically, EBX which was holding a pointer to the memory to access now holds part of the value to exchange in memory leading to .. well.. FAIL!
How were going to solve this is another matter but well do it !
[Reply ↓][177]
59. ![][27][esr][28] on [2010-02-14 at 14:01:05][178] said:
Just to round out the thread, heres the code from GPSD that I had in mind in the original post:
#define isgps_parityok(w) (isgps_parity(w) == ((w) & 0x3f))
#if 0
/*
* ESR found a doozy of a bug...
*
* Defining the above as a function triggers an optimizer bug in gcc 3.4.2.
* The symptom is that parity computation is screwed up and the decoder
* never achieves sync lock. Something steps on the argument to
* isgpsparity(); the lossage appears to be related to the compiler's
* attempt to fold the isgps_parity() call into isgps_parityok() in some
* tail-recursion-like manner. This happens under -O2, but not -O1, on
* both i386 and amd64. Disabling all of the individual -O2 suboptions
* does *not* fix it.
*
* And the fun doesn't stop there! It turns out that even with this fix, bare
* -O2 generates bad code. It takes "-O2 -fschedule-insns" to generate good
* code under 3.4.[23]...which is weird because -O2 is supposed to *imply*
* -fschedule-insns.
*
* gcc 4.0 does not manifest these bugs.
*/
static bool isgps_parityok(isgps30bits_t w)
{
return (isgpsparity(w) == (w & 0x3f));
}
#endif
In this case, the final confirmation that I had run into a real optimizer bug was the fact that GCC 4.0 fixed it.
[Reply ↓][179]
60. ![][87][John Regehr][88] on [2010-02-14 at 15:55:41][180] said:
I felt that the issue of compiler bugs required a separate discussion from generic heisenbugs, so I wrote it here:
<http://blog.regehr.org/archives/26>
**ESR says: Sound points, clearly stated and well sustained. Excellent!**
[Reply ↓][181]
61. ![][24]Frank Ch. Eigler on [2010-02-14 at 18:22:54][182] said:
“In this case, the final confirmation that I had run into a real optimizer bug was the fact that GCC 4.0 fixed it.”
Eric, that by itself in no way confirms this. There were many changes between 3.4 and 4.0 that interjected a whole new layer of optimization (SSA/GIMPLE), which pessimized some code.
What you need is real root cause analysis. If you are not able to interpret the assembly fully (use -fverbose-asm and internal-state-dumping options) combined with the more arcane aspects of the language rules, bring the issue to the attention of the gcc guys with the right expertise.
[Reply ↓][183]
62. ![][184]Brett Cox on [2010-02-14 at 18:47:30][185] said:
“In this case, the final confirmation that I had run into a real optimizer bug was the fact that GCC 4.0 fixed it.”
This proves only that that GCC 4.0 sublimated the error not that the error existed in the optimiser.
This is the basics of deductive logic, you statement is far too categorical.
[Reply ↓][186]
63. ![][152][Jeff Bonwick][153] on [2010-02-15 at 02:30:33][187] said:
Frank and Brett are exactly right.
You can claim its a compiler bug when you can show the incorrect generated instruction sequence.
Otherwise youre just guessing.
[Reply ↓][188]
64. ![][189]Mark on [2010-02-15 at 04:31:24][190] said:
Just to chime in briefly…Ive been developing compiler backends for around 16 years.
1\. 99.99% of the time (if not more often) when people turn on the optimizer and something breaks, its due to bugs in their code, not the optimizer. Thats my experience of having many bug reports where once we actually dig into the generated code with the user, it turns out to be that an uninitialized variable in their code ends up with different random values with & without the optimizer, or something similar (writing past the end of an array, using a compiler option that basically says that you are promising you never violate the aliasing rules of the language, etc.).
2\. Totally agree with people who say to turn on warnings. As many as you can tolerate. Its likely to find a lot of these things. Likewise, static analysis and dynamic analysis (like the /RTC1 option on MS VC++) are likely to find many more of these things that seem to be “optimizer bugs”.
3\. Any sane development team will have a rule that you have to do a release build with optimization on and pass tests before you check in, and will have daily test runs that run on debug builds, optimized debug builds (i.e. asserts and other checks left in), and release builds. These same teams should require actually understanding failures that show up when optimizations are enabled rather than just blaming the optimizer and turning it off for a section of code or a file.
The quickest “dumb” way to track down optimizer bugs (or supposed bugs) in a statically compiled language is to binary search the object files by generating a set of object files that are not optimized, and a set of object files that are optimized. After swapping objects in until you can determine the one object that has an issue, you can use whatever vendor-specific pragma enables/disables optimizations for a given function and binary search the functions in the object file. This doesnt work so well when you have inlining enabled, so the first thing to try is disabling inlining with your compiler to confirm that the issue still exists with inlining off. If it doesnt, then it will be harder to track down. Once you determine the problematic function, you can focus on the code that is generated to try to determine if its really an optimization bug or a bug in your code.
One other thing, I havent used gcc in years, but if its true that enabling generation of debug information actually changes the code that is generated, then its horribly broken. It shouldnt. Thats just stupid design.
[Reply ↓][191]
65. ![][192][Anthony Williams][193] on [2010-02-15 at 04:53:36][194] said:
Ive found a lot of compiler bugs in my time, so those of you who havent should count yourselves lucky. However, most of them have been in the frontend rather than the optimizer — code that should have been accepted wasnt, or code that should have been rejected was accepted.
Though optimizers do have bugs, they also tend to expose bugs in the code being compiled — the code makes an assumption that is not guaranteed to hold, but happens to be true for low optimization levels, but not for high optimization levels. This often corresponds to things such as use of uninitialized variables. Ive also seen cases where optimization changes the ABI (e.g. an enum which fits in 8 bits is an 8-bit variable at high optimization and a 32-bit variable at low optimization). This can break code where different compiler options are used for different source files.
Warnings can help, as can static analysers such as lint, and things like valgrind, but if youve followed all their recommendations and you still have a bug then you really need to pin down what the generated code is doing, and how it differs from what you expect. It might still turn out that your expectations are wrong.
[Reply ↓][195]
66. ![][103]Jake Fischer on [2010-02-15 at 05:17:29][196] said:
>> I’m not aware that esr has done any significant compiler work though.
>>
> I’ve written a couple of retrocompilers. I cheated by having them compile to C, though, and letting the low-level code generation be someone else’s problem.
So:
a) you didnt state the reference (<http://catb.org/retro/charter.html>)
b) my point stands.
[Reply ↓][197]
67. ![][19][Jay Maynard][20] on [2010-02-15 at 13:04:50][198] said:
Just to wrap up: Ivan was correct. He supplied a patch that used a different register for the assembler assist than had been used, and the problem disappeared.
Personally, I believe that the optimizers job is “first do no harm”. If code breaks due to the optimizer level, then its violated that rule. Now, with that said, Hercules is pushing the bounds of the C standard if not outright breaking them by using the assembler assist. Its utterly necessary, since the purpose of the assist is to guarantee correct behavior of the emulated machine by correctly guaranteeing the integrity of an emulated multiprocessor system and emulated I/O on a multiprocessor host system, so that emulated memory locations do not change in the middle of an emulated instruction as defined by the mainframes Principles of Operation manual. This means using the host processors interlocked storage instructions (in this case, “lock cmpxchg8b”), and since theres no way to do that in C, we had to do it ourselves.
The problem came when the C compiler decided to use one of the registers that the assembler assist thought was available for its own use for something else. We wound up changing the register we used, and the problem went away.
I dont know if theres a better way to have found this problem. If it werent for this discussion, wed have left it as it was and depended on the extra trace call to keep the compiler from screwing things up. That would have worked. Would it have broken later? Got me. Probably.
[Reply ↓][199]
68. ![][38]Dan on [2010-02-15 at 21:52:00][200] said:
There really needs to be a post about why “magic button” features (like optimization) in compilers are bad.
Its not that the optimizers per se are bad lots of clever people have written some great code to implement these optimizers so dont confuse my antipathy for optimizers with derision directed at their work.
From a formal perspective, optimizers kill any hope of making affirmative assertions about the integrity of your code. It is literally changing the recipe, in unknown ways, as the plate is headed out the door to the customer. I may have formally documented my system from the highest abstraction down to the source code, then the rug is pulled from under me by the optimizer.
To me, it is unacceptable to hand my code over to some black magic in the hope that it will make it run faster and/or occupy less memory. I designed a system upon a set of interactions in what way can I now guarantee the integrity of those interactions? If I understand my code so well, and the optimization mechanisms also, why am I not encoding such optimizations into my system directly where I can formally analyze their impact?
To use magical compiler optimization is an admission of failure. A cop-out. Laziness. An implicit declaration of the limits of ones understanding of ones own code “I dont know how to fix it, but if I push this magic button, itll run faster”.
So when I hear of problems like this, I think “well, thats what happens when you dont understand your own code”. Its also tangentially symptomatic of the tragic state of software engineering in general.
[Reply ↓][201]
69. ![][136]Roger Phillips on [2010-02-15 at 22:42:43][202] said:
>To use ‘magical’ compiler optimization is an admission of failure. A cop-out. Laziness. An implicit declaration of the limits of ones understanding of ones own code â€" “I don’t know how to fix it, but if I push this magic button, it’ll run faster”.
One wonders what youre going on about here. Optimizers are not magical; as a general rule, correctness of optimizations has a very definite formal definition. Furthermore, optimizing out instruction-level inefficiencies has nothing to do with system design. I suspect that you dont know a thing about formal analysis of programs.
[Reply ↓][203]
70. ![][38]Dan on [2010-02-15 at 23:24:45][204] said:
Roger, I suspect you dont know what a formal approach to software dev actually is, or you wouldnt say such silly things.
Hence, Im sure you do indeed “wonder what Im going on about”
[Reply ↓][205]
71. ![][206]J. Lapin on [2010-02-16 at 00:18:10][207] said:
For the record, I dont think that Dan, esr or Jay know what theyre talking about in this thread.
[Reply ↓][208]
72. ![][136]Roger Phillips on [2010-02-16 at 00:31:37][209] said:
>Roger, I suspect you don’t know what a ‘formal approach’ to software dev actually is, or you wouldn’t say such silly things.
Wrong answer. I work with formal methods every day.
[Reply ↓][210]
73. ![][152][Jeff Bonwick][153] on [2010-02-16 at 00:40:01][211] said:
If the issue is as Jay describes, then its neither an optimizer bug nor a coding bug per se — rather, its the fact that in-line assembly generally does not have a well-defined interaction with generated code. Its one thing to write an entire routine in assembly — as long as you follow the ABI youll be fine. But if you try to stick a bit of assembly in the middle of a C function, its rarely maintainable because you have no control over which local variables are in which registers. Personally I think its a bug that compilers let you do this at all. If you really need to use assembly, write a .s file.
[Reply ↓][212]
74. ![][152][Jeff Bonwick][153] on [2010-02-16 at 00:47:08][213] said:
@Dan — Im not sure what youre getting at. Unless you want to write everything in assembly, youre going to be using a compiler. The compilers job is to produce a mathematically correct mapping of your source code onto the target instruction set. This isnt magic, its entirely deterministic.
[Reply ↓][214]
75. ![][38]Dan on [2010-02-16 at 08:35:05][215] said:
_The compiler’s job is to produce a mathematically correct mapping of your source code onto the target instruction set._
This would be wonderful if it were true. Sadly, most compilers have been informally worried into shape over the years. Please point me at the formal proof of a popular compiler…Id love to make use of it.
_This isn’t magic, it’s entirely deterministic._
Of course it is. My use of the term “magic” was to describe the manner in which I have often witnessed such features being used “just hit the magical optimizer button and my code will perform better”
[Reply ↓][216]
76. ![][15][morgan greywolf][16] on [2010-02-16 at 12:24:50][217] said:
@Dan: The reason for the two phenomenon you point out: that popular compilers lack formal mathematical proof and the use of the optimizer buttons as “magic” are simply artifacts of the realities of software development in the real world. In academia, computer science is very concerned with correct, formal mathematical proofs; in the real world, we have no time for such things. There are deadlines to meet, code to write, bugs to be fixed.
This lack created a discipline known as “software engineering” whereby engineering principles are applied to software development. From this we get the Software Development Lifecycle (SDLC), waterfall diagrams, formal requirements documents, formal specifications documents, and metrics that compare the progress of development with the specifications. The problem was the same: we have no time for such things: there are deadlines to meet, code to write, bugs to be fixed.
So then we come to the de jure popular development model — [extreme programming][218]. Extreme Programming, a type of “agile process,” adopts some of the best ideas from the [bazaar open source model][219], but then attempts to twist it into contortions to make it palatable to managers, who understand nothing about software development.
At the end of the day, no matter how its done, I often see programmers within business organizations kind of “defaulting” to the less formal, more chaotic methods of the bazaar model anytime the best “managed” software development models seem to fail — which happens in almost all software projects.
It is my contention that the bazaar open source model of development is actually the most natural software development methodology, and that programmers will naturally tend towards it if left to their own devices.
[Reply ↓][220]
77. ![][38]Dan on [2010-02-16 at 13:49:38][221] said:
I assure you, Morgan, that I am well aware of the realities of our profession :) I have witnessed many fashions come and go over the past couple decades. I dont dispute any of this, nor indeed do I particularly object…you do what ya gotta do to get the job done.
My whole emphasis in this thread was my specific personal objection to the use of “magical” optimization…sure, in certain circumstances, where the effect is understood (and can be constrained) even I might conceivably opt to use them but then the “magical” aspect will have evaporated due to the level of understanding.
Generally, no, I dont use them. I dont need to. My approach to software engineering is heavily influenced by my background in formal methods. I have cultivated a pragmatic balance between hacking and formality that accommodates the real-world time & money constraints that face business. You are correct in asserting that the “Ivory Tower” academic formal methods approach is unmarketable. I strove to understand _why_ that was so, and what could be usefully/productively transferred across to the private sector.
I believe I have succeeded. I write clean, consistent, efficient code using a measure of formalism at higher levels of abstraction, and quality tools to support my emphasis on construction correctness. I take no longer than might be considered reasonable to do it, I dont lean on “magical” features, and the longer term payoff is realized in drastically reduced maintenance.
With respect to the various “managed” development methodologies that have won & lost favor over the years, one of my favorite essays [is this][222]. Amusing.
[Reply ↓][223]
78. ![][224][Tom DeGisi][225] on [2010-02-16 at 15:14:19][226] said:
Dan,
Got any favorite essays that explain your practical approach to formalism in software construction?
Yours,
Tom
[Reply ↓][227]
79. ![][38]Dan on [2010-02-16 at 17:00:24][228] said:
Not really, Tom…sorry….I didnt learn it from anybody. At least, at the time I was figuring this stuff out for myself, there was only heavyweight formal theory being taught. I am actually working on an eBook that I would like to self-publish online for free (with a PayPal hat left out for voluntary contributions!), but it seems that [this dude][229] has beaten me to the punch. I have yet to read his book, but it seems like it will be familiar to me.
My formal notation of choice is Z. I make use of Z/EVES & PowerProof. Im a huge fan of [Praxis and their SPARK toolkit][230] for constructing Ada code. But Im pretty language-agnostic really…C/C++, Ada, Java, Flex…whatever fits best.
[Reply ↓][231]
80. ![][232]Jeff Read on [2010-02-16 at 19:00:24][233] said:
Would that engineering principles _were_ applied to software development! Then software engineers would give mathematical assurance that their program functions as designed, under pain of going to prison and/or being fined a lot of money, the way civil engineers do for their roads and bridges. We would have drastically lessened the chances of a three-peat of the Therac-25 horror…
[Reply ↓][234]
81. ![][224][Tom DeGisi][225] on [2010-02-16 at 20:14:22][235] said:
Jeff,
Texas has (or had) professional software engineers by law. Dont know if it has helped, since people are still allowed to write software without being professional software engineers. They just cant call themselves engineers.
Yours,
Tom
[Reply ↓][236]
82. ![][38]Dan on [2010-02-17 at 08:35:36][237] said:
Thats interesting, Tom.
But asides from applying a standard before being legally allowed to adopt a label, are their any liability consequnces for being/not being an “engineer”?
Coz thats where the rubber really meets the road…
[Reply ↓][238]
83. ![][38]Dan on [2010-02-17 at 08:37:00][239] said:
*there*, dammit
esr…edit plugin, stat! ;)
[Reply ↓][240]
84. ![][224][Tom DeGisi][225] on [2010-02-17 at 14:17:35][241] said:
Yes, there are liability consequences.
[Stinking Badges][242]
According to Wikipedia, you cant call yourself a software engineer in 48 states.
[Software engineering professionalism][243]
Yours,
Tom
[Reply ↓][244]
85. ![][245][wheels][246] on [2010-02-17 at 23:45:14][247] said:
I ran into a bug once that was caused by a compiler generating code that was *logically* correct as optimized, and would have worked correctly in most cases, but was incorrect in the context of low-level programming of the processor. I was accessing processor peripheral registers that had to be written with 16-bit writes, but the compiler *always* optimized to 8-bit writes if it determined that only half the register was being modified.
The vendor changed subsequent releases of the compiler so that anything declared as a volatile 16-bit value was only accessed with 16-bit operations, but I had to use assembly in my code in order to make my release date.
[Reply ↓][248]
86. ![][249]Garrett on [2010-02-18 at 13:20:48][250] said:
Jeff:
Ontario (and several other Canadian provinces) recently changed their engineering licensing as well as education certification to include Engineering as a licensed engineering discipline. I was part of the 2nd cohort of students to graduate from such a program. The Therac disaster was one of the leading reasons for making that change.
That having been said, you cant assume that just because the profession exists that all of your problems will go away. Even in construction thats not true. In most states you dont need to have an engineer sign off on work to install a residential concrete driveway, for example. (Yes, you may need meet building codes and get a permit, but that doesnt mean you need to have an engineer sign off on the design). A 30-story high-rise is going to need engineer certification.
The basic mantra of engineering is that “people could die”. This means that a lot of software engineering methodology and analysis is needed for things like flight control software or medical devices. Large amounts of paperwork, possible formal methods and so on. Your word processor isnt going to kill someone if it fails. Your television control software wont (unless you have to worry about software-controlled over-voltages, or something, but thats becoming less of a worry as time goes on, not more). In short, most of the software you interact with on a day-to-day basis doesnt really matter. If it doesnt work your life becomes inconvenient, but no actual harm will come. Under such conditions, faster, cheaper development is more important than formal proofs.
One of these days Id love to see someone do a formal proof for Windows Notepad or grep on Linux. It would be pointless, but at least somewhat entertaining.
Garrett
[Reply ↓][251]
87. ![][38]Dan on [2010-02-19 at 16:52:45][252] said:
**_…One of these days I’d love to see someone do a formal proof for Windows Notepad…_**
Now that would be a form of torture that would make even this dour hermit blanche.
_I just threw up a little in my mouth…_
[Reply ↓][253]
88. ![][254][James][255] on [2014-03-01 at 18:29:04][256] said:
From ancient days when I worked on compilers for a living, I will never forget the complaint we received from someone when we came out with our new compiler that actually did serious optimization. The customer had code that,. I am not making this up, pretty well matched *the* standard example of undefined behavior in K&R,. i.e.
a[i++] = i;
The customer did not feel that he should have to find all the places his code did things with undefined resultsand it could be argued that our compiler should have pointed it out. (I do not know what the ultimate response to the customer was.)
I am glad that others have pointed out that optimizers can trip up code whose behavior is officially undefinedand also glad that the true cause of the Hercules issue has been found.
[Reply ↓][257]
89. ![][258]bob on [2014-03-01 at 19:38:20][259] said:
I agree with everything in the article except the statement that optimization bugs are on the whole rare. I actually during the years i wrote C full time, found them to be quite common. Personally, I prefer to turn off optimization. I find it reduces heisenbugs to zero.
[Reply ↓][260]
90. ![][261][pcloutier@progenygenealogy.com][262] on [2014-03-02 at 08:51:35][263] said:
Optimization bugs are _not_ rare. After finding too many problems due to structure mis-alignments in code compiled with MS Visual Studio, we turned off optimization permanently in our production code. Its just not worth the trouble.
[Reply ↓][264]
* ![][106][esr][28] on [2014-03-02 at 09:41:17][265] said:
>Optimization bugs are _not_ rare.
They probably arent, in Microsoft compilers. Open-source compilers have a better record.
[Reply ↓][266]
91. ![][267]OCD on [2014-03-02 at 10:34:13][268] said:
Dan, thanks for using the hyphen properly on the word “anally-bound.” That is the correct way to spell that.
[Reply ↓][269]
### Leave a Reply [Cancel reply][270]
Your email address will not be published. Required fields are marked *
Comment
Name *
Email *
Website
Notify me of follow-up comments by email.
Notify me of new posts by email.
### Tip Jar
Donate here to support my open-source projects. Small but continuing donations via Patreon help more than one-time donations via PayPal.
![][271]
![Patreon][272]
### Archives
* [February 2018][273]
* [January 2018][274]
* [December 2017][275]
* [November 2017][276]
* [October 2017][277]
* [September 2017][278]
* [August 2017][279]
* [July 2017][280]
* [June 2017][281]
* [May 2017][282]
* [April 2017][283]
* [March 2017][284]
* [February 2017][285]
* [January 2017][286]
* [December 2016][287]
* [September 2016][288]
* [August 2016][289]
* [July 2016][290]
* [June 2016][291]
* [May 2016][292]
* [April 2016][293]
* [March 2016][294]
* [February 2016][295]
* [January 2016][296]
* [December 2015][297]
* [November 2015][298]
* [October 2015][299]
* [September 2015][300]
* [August 2015][301]
* [July 2015][302]
* [June 2015][303]
* [May 2015][304]
* [April 2015][305]
* [March 2015][306]
* [February 2015][307]
* [January 2015][308]
* [December 2014][309]
* [November 2014][310]
* [October 2014][311]
* [September 2014][312]
* [August 2014][313]
* [July 2014][314]
* [June 2014][315]
* [May 2014][316]
* [April 2014][317]
* [March 2014][318]
* [February 2014][319]
* [January 2014][320]
* [December 2013][321]
* [November 2013][322]
* [October 2013][323]
* [September 2013][324]
* [August 2013][325]
* [July 2013][326]
* [June 2013][327]
* [May 2013][328]
* [April 2013][329]
* [March 2013][330]
* [February 2013][331]
* [January 2013][332]
* [December 2012][333]
* [November 2012][334]
* [October 2012][335]
* [September 2012][336]
* [August 2012][337]
* [July 2012][338]
* [June 2012][339]
* [May 2012][340]
* [April 2012][341]
* [March 2012][342]
* [February 2012][343]
* [January 2012][344]
* [December 2011][345]
* [November 2011][346]
* [October 2011][347]
* [September 2011][348]
* [August 2011][349]
* [July 2011][350]
* [June 2011][351]
* [May 2011][352]
* [April 2011][353]
* [March 2011][354]
* [February 2011][355]
* [January 2011][356]
* [December 2010][357]
* [November 2010][358]
* [October 2010][359]
* [September 2010][360]
* [August 2010][361]
* [July 2010][362]
* [June 2010][363]
* [May 2010][364]
* [April 2010][365]
* [March 2010][366]
* [February 2010][367]
* [January 2010][368]
* [December 2009][369]
* [November 2009][370]
* [October 2009][371]
* [September 2009][372]
* [August 2009][373]
* [July 2009][374]
* [June 2009][375]
* [May 2009][376]
* [April 2009][377]
* [March 2009][378]
* [February 2009][379]
* [January 2009][380]
* [December 2008][381]
* [November 2008][382]
* [October 2008][383]
* [September 2008][384]
* [August 2008][385]
* [July 2008][386]
* [June 2008][387]
* [June 2006][388]
* [May 2006][389]
* [April 2006][390]
* [March 2006][391]
* [February 2006][392]
* [January 2006][393]
* [December 2005][394]
* [November 2005][395]
* [September 2005][396]
* [August 2005][397]
* [July 2005][398]
* [February 2005][399]
* [January 2005][400]
* [December 2004][401]
* [November 2004][402]
* [October 2004][403]
* [September 2004][404]
* [February 2004][405]
* [January 2004][406]
* [December 2003][407]
* [November 2003][408]
* [October 2003][409]
* [September 2003][410]
* [August 2003][411]
* [July 2003][412]
* [June 2003][413]
* [May 2003][414]
* [April 2003][415]
* [December 2002][416]
* [November 2002][417]
* [October 2002][418]
* [September 2002][419]
* [July 2002][420]
* [June 2002][421]
* [May 2002][422]
### Meta
* [Log in][423]
* [Entries RSS][424]
* [Comments RSS][425]
* [WordPress.org][426]
### Hacker Emblem
![][427]
### Eric Conspiracy
![][428]
### Anti-Idiotarian Manifesto
![][429]
© 2018 [ Armed and Dangerous ][1]
[Admired Theme][430]
[1]: http://esr.ibiblio.org/ "Armed and Dangerous"
[2]: http://esr.ibiblio.org#content "Skip to primary content"
[3]: http://esr.ibiblio.org#secondary "Skip to secondary content"
[4]: http://esr.ibiblio.org/
[5]: http://esr.ibiblio.org/?p=1696
[6]: http://esr.ibiblio.org/?p=1713
[7]: http://esr.ibiblio.org/?p=1705 "09:57:29"
[8]: http://esr.ibiblio.org/?author=2 "View all posts by Eric Raymond"
[9]: http://en.wikipedia.org/wiki/Unusual_software_bug
[10]: https://lh6.googleusercontent.com/-tY2Av1p7TWU/AAAAAAAAAAI/AAAAAAAABaE/80iMm0zkP_Y/photo.jpg?sz=40
[11]: https://plus.google.com/+EricRaymond
[12]: http://esr.ibiblio.org/?cat=13
[13]: http://esr.ibiblio.org/?author=2
[14]: http://esr.ibiblio.org/?p=1705 "Permalink to When you see a heisenbug in C, suspect your compilers optimizer"
[15]: http://0.gravatar.com/avatar/978a382855e92c89af50d6c75a9b0c6f?s=68&d=mm&r=g
[16]: http://robsworldoftech.blogspot.com
[17]: http://esr.ibiblio.org/?p=1705#comment-248137
[18]: http://esr.ibiblio.org/?p=1705&replytocom=248137#respond
[19]: http://2.gravatar.com/avatar/b2f758e061500bbc4678a8c3f477d05a?s=68&d=mm&r=g
[20]: http://www.tronguy.net
[21]: http://esr.ibiblio.org/?p=1705#comment-248139
[22]: http://www.hercules-390.org
[23]: http://esr.ibiblio.org/?p=1705&replytocom=248139#respond
[24]: http://0.gravatar.com/avatar/34c49c1c354607b40f57e029b4cdee30?s=68&d=mm&r=g
[25]: http://esr.ibiblio.org/?p=1705#comment-248141
[26]: http://esr.ibiblio.org/?p=1705&replytocom=248141#respond
[27]: http://1.gravatar.com/avatar/131a55e547345f3123af2c4ddd49e6a6?s=68&d=mm&r=g
[28]: http://www.catb.org/~esr/
[29]: http://esr.ibiblio.org/?p=1705#comment-248145
[30]: http://esr.ibiblio.org/?p=1705&replytocom=248145#respond
[31]: http://0.gravatar.com/avatar/9c9ea80a2d8d6561d9f364d4c26d7105?s=68&d=mm&r=g
[32]: http://esr.ibiblio.org/?p=1705#comment-248146
[33]: http://esr.ibiblio.org/?p=1705&replytocom=248146#respond
[34]: http://esr.ibiblio.org/?p=1705#comment-248147
[35]: http://esr.ibiblio.org/?p=1705&replytocom=248147#respond
[36]: http://esr.ibiblio.org/?p=1705#comment-248150
[37]: http://esr.ibiblio.org/?p=1705&replytocom=248150#respond
[38]: http://0.gravatar.com/avatar/c510febb9bed68b5cc4a09f076701e0f?s=68&d=mm&r=g
[39]: http://esr.ibiblio.org/?p=1705#comment-248151
[40]: http://esr.ibiblio.org/?p=1705&replytocom=248151#respond
[41]: http://1.gravatar.com/avatar/414d48de3871205c341f6a14b8ced193?s=68&d=mm&r=g
[42]: http://rosettacode.org/wiki/User:Short_Circuit
[43]: http://esr.ibiblio.org/?p=1705#comment-248152
[44]: http://esr.ibiblio.org/?p=1705&replytocom=248152#respond
[45]: http://esr.ibiblio.org/?p=1705#comment-248153
[46]: http://esr.ibiblio.org/?p=1705&replytocom=248153#respond
[47]: http://esr.ibiblio.org/?p=1705#comment-248155
[48]: http://esr.ibiblio.org/?p=1705&replytocom=248155#respond
[49]: http://1.gravatar.com/avatar/1ef9b05ce05b1af113e2654cad5b872e?s=68&d=mm&r=g
[50]: http://esr.ibiblio.org/?p=1705#comment-248156
[51]: http://esr.ibiblio.org/?p=1705&replytocom=248156#respond
[52]: http://0.gravatar.com/avatar/fcc0b346aa7491dfeada492ce5fcf561?s=68&d=mm&r=g
[53]: http://www.jgc.org/
[54]: http://esr.ibiblio.org/?p=1705#comment-248158
[55]: http://esr.ibiblio.org/?p=1705&replytocom=248158#respond
[56]: http://esr.ibiblio.org/?p=1705#comment-248160
[57]: http://esr.ibiblio.org/?p=1705&replytocom=248160#respond
[58]: http://1.gravatar.com/avatar/18e87c8bdc46d99c7b37b0249320f490?s=68&d=mm&r=g
[59]: http://esr.ibiblio.org/?p=1705#comment-248161
[60]: http://esr.ibiblio.org/?p=1705&replytocom=248161#respond
[61]: http://2.gravatar.com/avatar/80c86ee1b95d452cd7b183916c426abe?s=68&d=mm&r=g
[62]: http://esr.ibiblio.org/?p=1705#comment-248166
[63]: http://esr.ibiblio.org/?p=1705&replytocom=248166#respond
[64]: http://esr.ibiblio.org/?p=1705#comment-248168
[65]: http://esr.ibiblio.org/?p=1705&replytocom=248168#respond
[66]: http://0.gravatar.com/avatar/61f10ec2a65f027f6a81d23d463d1131?s=68&d=mm&r=g
[67]: http://newstechnica.com
[68]: http://esr.ibiblio.org/?p=1705#comment-248170
[69]: http://esr.ibiblio.org/?p=1705&replytocom=248170#respond
[70]: http://1.gravatar.com/avatar/afc99c1a84af63c4470033efe325a8da?s=68&d=mm&r=g
[71]: http://esr.ibiblio.org/?p=1705#comment-248171
[72]: http://esr.ibiblio.org/?p=1705&replytocom=248171#respond
[73]: http://0.gravatar.com/avatar/998babd3e7e990423f6e63ab342f2219?s=68&d=mm&r=g
[74]: http://williambswift.blogspot.com/
[75]: http://esr.ibiblio.org/?p=1705#comment-248172
[76]: http://esr.ibiblio.org/?p=1705&replytocom=248172#respond
[77]: http://esr.ibiblio.org/?p=1705#comment-248173
[78]: http://esr.ibiblio.org/?p=1705&replytocom=248173#respond
[79]: http://esr.ibiblio.org/?p=1705#comment-248174
[80]: http://esr.ibiblio.org/?p=1705&replytocom=248174#respond
[81]: http://esr.ibiblio.org/?p=1705#comment-248175
[82]: http://esr.ibiblio.org/?p=1705&replytocom=248175#respond
[83]: http://esr.ibiblio.org/?p=1705#comment-248176
[84]: http://esr.ibiblio.org/?p=1705&replytocom=248176#respond
[85]: http://esr.ibiblio.org/?p=1705#comment-248177
[86]: http://esr.ibiblio.org/?p=1705&replytocom=248177#respond
[87]: http://0.gravatar.com/avatar/3ccaf45d7ab8ecc0e412fe911c9b9d10?s=68&d=mm&r=g
[88]: http://www.cs.utah.edu/~regehr/
[89]: http://esr.ibiblio.org/?p=1705#comment-248179
[90]: http://esr.ibiblio.org/?p=1705&replytocom=248179#respond
[91]: http://esr.ibiblio.org/?p=1705#comment-248180
[92]: http://esr.ibiblio.org/?p=1705&replytocom=248180#respond
[93]: http://0.gravatar.com/avatar/67738902000bf8c0810023db800b1703?s=68&d=mm&r=g
[94]: http://www.losethos.com
[95]: http://esr.ibiblio.org/?p=1705#comment-248181
[96]: http://esr.ibiblio.org/?p=1705&replytocom=248181#respond
[97]: http://esr.ibiblio.org/?p=1705#comment-248183
[98]: http://esr.ibiblio.org/?p=1705&replytocom=248183#respond
[99]: http://0.gravatar.com/avatar/3eabefbf82c2001045480b85e092a826?s=68&d=mm&r=g
[100]: http://9fans.net/
[101]: http://esr.ibiblio.org/?p=1705#comment-248186
[102]: http://esr.ibiblio.org/?p=1705&replytocom=248186#respond
[103]: http://2.gravatar.com/avatar/511009ee05c27d2dbb6ed1c0117661d8?s=68&d=mm&r=g
[104]: http://esr.ibiblio.org/?p=1705#comment-248187
[105]: http://esr.ibiblio.org/?p=1705&replytocom=248187#respond
[106]: http://1.gravatar.com/avatar/131a55e547345f3123af2c4ddd49e6a6?s=39&d=mm&r=g
[107]: http://esr.ibiblio.org/?p=1705#comment-248191
[108]: http://esr.ibiblio.org/?p=1705&replytocom=248191#respond
[109]: http://0.gravatar.com/avatar/9915581a6d4ce55d701c912019ea040f?s=68&d=mm&r=g
[110]: http://esr.ibiblio.org/?p=1705#comment-248189
[111]: http://esr.ibiblio.org/?p=1705&replytocom=248189#respond
[112]: http://esr.ibiblio.org/?p=1705#comment-248190
[113]: http://esr.ibiblio.org/?p=1705&replytocom=248190#respond
[114]: http://0.gravatar.com/avatar/9fed881ec630fc5b36f29c8daa9704cd?s=68&d=mm&r=g
[115]: http://esr.ibiblio.org/?p=1705#comment-248192
[116]: http://esr.ibiblio.org/?p=1705&replytocom=248192#respond
[117]: http://esr.ibiblio.org/?p=1705#comment-248196
[118]: http://esr.ibiblio.org/?p=1705&replytocom=248196#respond
[119]: http://1.gravatar.com/avatar/a92492d7ad1ce7a55d2e411f70745e2f?s=68&d=mm&r=g
[120]: https://cajo.dev.java.net
[121]: http://esr.ibiblio.org/?p=1705#comment-248197
[122]: http://esr.ibiblio.org/?p=1705&replytocom=248197#respond
[123]: http://2.gravatar.com/avatar/bbb1c69b64019a3df907c3545186f907?s=68&d=mm&r=g
[124]: http://boston.conman.org/
[125]: http://esr.ibiblio.org/?p=1705#comment-248198
[126]: http://esr.ibiblio.org/?p=1705&replytocom=248198#respond
[127]: http://esr.ibiblio.org/?p=1705#comment-248200
[128]: http://esr.ibiblio.org/?p=1705&replytocom=248200#respond
[129]: http://esr.ibiblio.org/?p=1705#comment-248201
[130]: http://esr.ibiblio.org/?p=1705&replytocom=248201#respond
[131]: http://0.gravatar.com/avatar/fc4e87404460de85f5317c60f73e6a5e?s=68&d=mm&r=g
[132]: http://esr.ibiblio.org/?p=1705#comment-248204
[133]: http://esr.ibiblio.org/?p=1705&replytocom=248204#respond
[134]: http://esr.ibiblio.org/?p=1705#comment-248205
[135]: http://esr.ibiblio.org/?p=1705&replytocom=248205#respond
[136]: http://2.gravatar.com/avatar/e779710678d6cf6d09fafc42f0184e62?s=68&d=mm&r=g
[137]: http://esr.ibiblio.org/?p=1705#comment-248206
[138]: http://esr.ibiblio.org/?p=1705&replytocom=248206#respond
[139]: http://esr.ibiblio.org/?p=1705#comment-248208
[140]: http://esr.ibiblio.org/?p=1705&replytocom=248208#respond
[141]: http://esr.ibiblio.org/?p=1705#comment-248210
[142]: http://esr.ibiblio.org/?p=1705&replytocom=248210#respond
[143]: http://1.gravatar.com/avatar/ac46efd39b35cac8c51a4b4b2e7163d5?s=68&d=mm&r=g
[144]: http://esr.ibiblio.org/?p=1705#comment-248211
[145]: http://esr.ibiblio.org/?p=1705&replytocom=248211#respond
[146]: http://0.gravatar.com/avatar/96dd777e397ab128fedab46af97a3a4a?s=68&d=mm&r=g
[147]: http://esr.ibiblio.org/?p=1705#comment-248216
[148]: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=325670
[149]: http://esr.ibiblio.org/?p=1705&replytocom=248216#respond
[150]: http://esr.ibiblio.org/?p=1705#comment-248217
[151]: http://esr.ibiblio.org/?p=1705&replytocom=248217#respond
[152]: http://1.gravatar.com/avatar/4d592ee3ca996b4fad0d0525ade67597?s=68&d=mm&r=g
[153]: http://blogs.sun.com/bonwick
[154]: http://esr.ibiblio.org/?p=1705#comment-248222
[155]: http://esr.ibiblio.org/?p=1705&replytocom=248222#respond
[156]: http://1.gravatar.com/avatar/71fb6907f27782c66036cfa1470938de?s=68&d=mm&r=g
[157]: http://esr.ibiblio.org/?p=1705#comment-248223
[158]: http://esr.ibiblio.org/?p=1705&replytocom=248223#respond
[159]: http://esr.ibiblio.org/?p=1705#comment-248224
[160]: http://esr.ibiblio.org/?p=1705&replytocom=248224#respond
[161]: http://esr.ibiblio.org/?p=1705#comment-248225
[162]: http://esr.ibiblio.org/?p=1705&replytocom=248225#respond
[163]: http://esr.ibiblio.org/?p=1705#comment-248226
[164]: http://esr.ibiblio.org/?p=1705&replytocom=248226#respond
[165]: http://esr.ibiblio.org/?p=1705#comment-248227
[166]: http://esr.ibiblio.org/?p=1705&replytocom=248227#respond
[167]: http://esr.ibiblio.org/?p=1705#comment-248229
[168]: http://esr.ibiblio.org/?p=1705&replytocom=248229#respond
[169]: http://esr.ibiblio.org/?p=1705#comment-248234
[170]: http://esr.ibiblio.org/?p=1705&replytocom=248234#respond
[171]: http://esr.ibiblio.org/?p=1705#comment-248237
[172]: http://esr.ibiblio.org/?p=1705&replytocom=248237#respond
[173]: http://esr.ibiblio.org/?p=1705#comment-248244
[174]: http://esr.ibiblio.org/?p=1705&replytocom=248244#respond
[175]: http://2.gravatar.com/avatar/50d3cc6c4dda64ba79f4e63ea5524ea8?s=68&d=mm&r=g
[176]: http://esr.ibiblio.org/?p=1705#comment-248245
[177]: http://esr.ibiblio.org/?p=1705&replytocom=248245#respond
[178]: http://esr.ibiblio.org/?p=1705#comment-248246
[179]: http://esr.ibiblio.org/?p=1705&replytocom=248246#respond
[180]: http://esr.ibiblio.org/?p=1705#comment-248257
[181]: http://esr.ibiblio.org/?p=1705&replytocom=248257#respond
[182]: http://esr.ibiblio.org/?p=1705#comment-248271
[183]: http://esr.ibiblio.org/?p=1705&replytocom=248271#respond
[184]: http://2.gravatar.com/avatar/272dc45f1fb3a8d0aeb967cdba533e55?s=68&d=mm&r=g
[185]: http://esr.ibiblio.org/?p=1705#comment-248272
[186]: http://esr.ibiblio.org/?p=1705&replytocom=248272#respond
[187]: http://esr.ibiblio.org/?p=1705#comment-248299
[188]: http://esr.ibiblio.org/?p=1705&replytocom=248299#respond
[189]: http://0.gravatar.com/avatar/920d64eab2e00a32f28ee5d64eae1534?s=68&d=mm&r=g
[190]: http://esr.ibiblio.org/?p=1705#comment-248300
[191]: http://esr.ibiblio.org/?p=1705&replytocom=248300#respond
[192]: http://0.gravatar.com/avatar/014ef33a9f0e7e3ac5a12e7446d2d619?s=68&d=mm&r=g
[193]: http://www.justsoftwaresolutions.co.uk/blog/
[194]: http://esr.ibiblio.org/?p=1705#comment-248302
[195]: http://esr.ibiblio.org/?p=1705&replytocom=248302#respond
[196]: http://esr.ibiblio.org/?p=1705#comment-248303
[197]: http://esr.ibiblio.org/?p=1705&replytocom=248303#respond
[198]: http://esr.ibiblio.org/?p=1705#comment-248328
[199]: http://esr.ibiblio.org/?p=1705&replytocom=248328#respond
[200]: http://esr.ibiblio.org/?p=1705#comment-248350
[201]: http://esr.ibiblio.org/?p=1705&replytocom=248350#respond
[202]: http://esr.ibiblio.org/?p=1705#comment-248353
[203]: http://esr.ibiblio.org/?p=1705&replytocom=248353#respond
[204]: http://esr.ibiblio.org/?p=1705#comment-248355
[205]: http://esr.ibiblio.org/?p=1705&replytocom=248355#respond
[206]: http://0.gravatar.com/avatar/6d9c1d96a0ba6316914e998872824880?s=68&d=mm&r=g
[207]: http://esr.ibiblio.org/?p=1705#comment-248356
[208]: http://esr.ibiblio.org/?p=1705&replytocom=248356#respond
[209]: http://esr.ibiblio.org/?p=1705#comment-248357
[210]: http://esr.ibiblio.org/?p=1705&replytocom=248357#respond
[211]: http://esr.ibiblio.org/?p=1705#comment-248358
[212]: http://esr.ibiblio.org/?p=1705&replytocom=248358#respond
[213]: http://esr.ibiblio.org/?p=1705#comment-248359
[214]: http://esr.ibiblio.org/?p=1705&replytocom=248359#respond
[215]: http://esr.ibiblio.org/?p=1705#comment-248383
[216]: http://esr.ibiblio.org/?p=1705&replytocom=248383#respond
[217]: http://esr.ibiblio.org/?p=1705#comment-248392
[218]: http://www.extremeprogramming.org/
[219]: http://catb.org/esr/writings/homesteading/
[220]: http://esr.ibiblio.org/?p=1705&replytocom=248392#respond
[221]: http://esr.ibiblio.org/?p=1705#comment-248396
[222]: http://www.cs.tufts.edu/~nr/cs257/archive/david-parnas/fake-it.pdf
[223]: http://esr.ibiblio.org/?p=1705&replytocom=248396#respond
[224]: http://0.gravatar.com/avatar/3c7fa8de33c9d4830b37d90ad81d5049?s=68&d=mm&r=g
[225]: http://winceandnod.blogspot.com
[226]: http://esr.ibiblio.org/?p=1705#comment-248398
[227]: http://esr.ibiblio.org/?p=1705&replytocom=248398#respond
[228]: http://esr.ibiblio.org/?p=1705#comment-248401
[229]: http://www.cup.cam.ac.uk/us/catalogue/catalogue.asp?isbn=0511500785
[230]: http://www.praxis-his.com/
[231]: http://esr.ibiblio.org/?p=1705&replytocom=248401#respond
[232]: http://0.gravatar.com/avatar/3a0504845c920c9d6cb0c55777ef6256?s=68&d=mm&r=g
[233]: http://esr.ibiblio.org/?p=1705#comment-248405
[234]: http://esr.ibiblio.org/?p=1705&replytocom=248405#respond
[235]: http://esr.ibiblio.org/?p=1705#comment-248409
[236]: http://esr.ibiblio.org/?p=1705&replytocom=248409#respond
[237]: http://esr.ibiblio.org/?p=1705#comment-248506
[238]: http://esr.ibiblio.org/?p=1705&replytocom=248506#respond
[239]: http://esr.ibiblio.org/?p=1705#comment-248507
[240]: http://esr.ibiblio.org/?p=1705&replytocom=248507#respond
[241]: http://esr.ibiblio.org/?p=1705#comment-248559
[242]: http://www.stevemcconnell.com/gr-badges.htm
[243]: http://en.wikipedia.org/wiki/Software_engineering_professionalism
[244]: http://esr.ibiblio.org/?p=1705&replytocom=248559#respond
[245]: http://1.gravatar.com/avatar/16a576a6f86f69a8404806bffc103313?s=68&d=mm&r=g
[246]: http://bendreth.com
[247]: http://esr.ibiblio.org/?p=1705#comment-248639
[248]: http://esr.ibiblio.org/?p=1705&replytocom=248639#respond
[249]: http://2.gravatar.com/avatar/b0e8f7429a6351d367e92a8fed85020e?s=68&d=mm&r=g
[250]: http://esr.ibiblio.org/?p=1705#comment-248716
[251]: http://esr.ibiblio.org/?p=1705&replytocom=248716#respond
[252]: http://esr.ibiblio.org/?p=1705#comment-248936
[253]: http://esr.ibiblio.org/?p=1705&replytocom=248936#respond
[254]: http://2.gravatar.com/avatar/5cae48a7d86cb8ecd4d756764c2b6ab1?s=68&d=mm&r=g
[255]: http://agingnerd.blogspot.com/
[256]: http://esr.ibiblio.org/?p=1705#comment-425387
[257]: http://esr.ibiblio.org/?p=1705&replytocom=425387#respond
[258]: http://2.gravatar.com/avatar/820d0e4ee14e986a44d33782ca852f51?s=68&d=mm&r=g
[259]: http://esr.ibiblio.org/?p=1705#comment-425391
[260]: http://esr.ibiblio.org/?p=1705&replytocom=425391#respond
[261]: http://2.gravatar.com/avatar/2da50f1dc1637221d4b650784f3f8802?s=68&d=mm&r=g
[262]: http://progenygenealogy.com
[263]: http://esr.ibiblio.org/?p=1705#comment-425425
[264]: http://esr.ibiblio.org/?p=1705&replytocom=425425#respond
[265]: http://esr.ibiblio.org/?p=1705#comment-425426
[266]: http://esr.ibiblio.org/?p=1705&replytocom=425426#respond
[267]: http://1.gravatar.com/avatar/7962497c380607e2b777e5af67464bac?s=68&d=mm&r=g
[268]: http://esr.ibiblio.org/?p=1705#comment-425429
[269]: http://esr.ibiblio.org/?p=1705&replytocom=425429#respond
[270]: /?p=1705#respond
[271]: https://www.paypalobjects.com/en_US/i/scr/pixel.gif
[272]: https://www.patreon.com/images/patreon_navigation_logo_negative.png
[273]: http://esr.ibiblio.org/?m=201802
[274]: http://esr.ibiblio.org/?m=201801
[275]: http://esr.ibiblio.org/?m=201712
[276]: http://esr.ibiblio.org/?m=201711
[277]: http://esr.ibiblio.org/?m=201710
[278]: http://esr.ibiblio.org/?m=201709
[279]: http://esr.ibiblio.org/?m=201708
[280]: http://esr.ibiblio.org/?m=201707
[281]: http://esr.ibiblio.org/?m=201706
[282]: http://esr.ibiblio.org/?m=201705
[283]: http://esr.ibiblio.org/?m=201704
[284]: http://esr.ibiblio.org/?m=201703
[285]: http://esr.ibiblio.org/?m=201702
[286]: http://esr.ibiblio.org/?m=201701
[287]: http://esr.ibiblio.org/?m=201612
[288]: http://esr.ibiblio.org/?m=201609
[289]: http://esr.ibiblio.org/?m=201608
[290]: http://esr.ibiblio.org/?m=201607
[291]: http://esr.ibiblio.org/?m=201606
[292]: http://esr.ibiblio.org/?m=201605
[293]: http://esr.ibiblio.org/?m=201604
[294]: http://esr.ibiblio.org/?m=201603
[295]: http://esr.ibiblio.org/?m=201602
[296]: http://esr.ibiblio.org/?m=201601
[297]: http://esr.ibiblio.org/?m=201512
[298]: http://esr.ibiblio.org/?m=201511
[299]: http://esr.ibiblio.org/?m=201510
[300]: http://esr.ibiblio.org/?m=201509
[301]: http://esr.ibiblio.org/?m=201508
[302]: http://esr.ibiblio.org/?m=201507
[303]: http://esr.ibiblio.org/?m=201506
[304]: http://esr.ibiblio.org/?m=201505
[305]: http://esr.ibiblio.org/?m=201504
[306]: http://esr.ibiblio.org/?m=201503
[307]: http://esr.ibiblio.org/?m=201502
[308]: http://esr.ibiblio.org/?m=201501
[309]: http://esr.ibiblio.org/?m=201412
[310]: http://esr.ibiblio.org/?m=201411
[311]: http://esr.ibiblio.org/?m=201410
[312]: http://esr.ibiblio.org/?m=201409
[313]: http://esr.ibiblio.org/?m=201408
[314]: http://esr.ibiblio.org/?m=201407
[315]: http://esr.ibiblio.org/?m=201406
[316]: http://esr.ibiblio.org/?m=201405
[317]: http://esr.ibiblio.org/?m=201404
[318]: http://esr.ibiblio.org/?m=201403
[319]: http://esr.ibiblio.org/?m=201402
[320]: http://esr.ibiblio.org/?m=201401
[321]: http://esr.ibiblio.org/?m=201312
[322]: http://esr.ibiblio.org/?m=201311
[323]: http://esr.ibiblio.org/?m=201310
[324]: http://esr.ibiblio.org/?m=201309
[325]: http://esr.ibiblio.org/?m=201308
[326]: http://esr.ibiblio.org/?m=201307
[327]: http://esr.ibiblio.org/?m=201306
[328]: http://esr.ibiblio.org/?m=201305
[329]: http://esr.ibiblio.org/?m=201304
[330]: http://esr.ibiblio.org/?m=201303
[331]: http://esr.ibiblio.org/?m=201302
[332]: http://esr.ibiblio.org/?m=201301
[333]: http://esr.ibiblio.org/?m=201212
[334]: http://esr.ibiblio.org/?m=201211
[335]: http://esr.ibiblio.org/?m=201210
[336]: http://esr.ibiblio.org/?m=201209
[337]: http://esr.ibiblio.org/?m=201208
[338]: http://esr.ibiblio.org/?m=201207
[339]: http://esr.ibiblio.org/?m=201206
[340]: http://esr.ibiblio.org/?m=201205
[341]: http://esr.ibiblio.org/?m=201204
[342]: http://esr.ibiblio.org/?m=201203
[343]: http://esr.ibiblio.org/?m=201202
[344]: http://esr.ibiblio.org/?m=201201
[345]: http://esr.ibiblio.org/?m=201112
[346]: http://esr.ibiblio.org/?m=201111
[347]: http://esr.ibiblio.org/?m=201110
[348]: http://esr.ibiblio.org/?m=201109
[349]: http://esr.ibiblio.org/?m=201108
[350]: http://esr.ibiblio.org/?m=201107
[351]: http://esr.ibiblio.org/?m=201106
[352]: http://esr.ibiblio.org/?m=201105
[353]: http://esr.ibiblio.org/?m=201104
[354]: http://esr.ibiblio.org/?m=201103
[355]: http://esr.ibiblio.org/?m=201102
[356]: http://esr.ibiblio.org/?m=201101
[357]: http://esr.ibiblio.org/?m=201012
[358]: http://esr.ibiblio.org/?m=201011
[359]: http://esr.ibiblio.org/?m=201010
[360]: http://esr.ibiblio.org/?m=201009
[361]: http://esr.ibiblio.org/?m=201008
[362]: http://esr.ibiblio.org/?m=201007
[363]: http://esr.ibiblio.org/?m=201006
[364]: http://esr.ibiblio.org/?m=201005
[365]: http://esr.ibiblio.org/?m=201004
[366]: http://esr.ibiblio.org/?m=201003
[367]: http://esr.ibiblio.org/?m=201002
[368]: http://esr.ibiblio.org/?m=201001
[369]: http://esr.ibiblio.org/?m=200912
[370]: http://esr.ibiblio.org/?m=200911
[371]: http://esr.ibiblio.org/?m=200910
[372]: http://esr.ibiblio.org/?m=200909
[373]: http://esr.ibiblio.org/?m=200908
[374]: http://esr.ibiblio.org/?m=200907
[375]: http://esr.ibiblio.org/?m=200906
[376]: http://esr.ibiblio.org/?m=200905
[377]: http://esr.ibiblio.org/?m=200904
[378]: http://esr.ibiblio.org/?m=200903
[379]: http://esr.ibiblio.org/?m=200902
[380]: http://esr.ibiblio.org/?m=200901
[381]: http://esr.ibiblio.org/?m=200812
[382]: http://esr.ibiblio.org/?m=200811
[383]: http://esr.ibiblio.org/?m=200810
[384]: http://esr.ibiblio.org/?m=200809
[385]: http://esr.ibiblio.org/?m=200808
[386]: http://esr.ibiblio.org/?m=200807
[387]: http://esr.ibiblio.org/?m=200806
[388]: http://esr.ibiblio.org/?m=200606
[389]: http://esr.ibiblio.org/?m=200605
[390]: http://esr.ibiblio.org/?m=200604
[391]: http://esr.ibiblio.org/?m=200603
[392]: http://esr.ibiblio.org/?m=200602
[393]: http://esr.ibiblio.org/?m=200601
[394]: http://esr.ibiblio.org/?m=200512
[395]: http://esr.ibiblio.org/?m=200511
[396]: http://esr.ibiblio.org/?m=200509
[397]: http://esr.ibiblio.org/?m=200508
[398]: http://esr.ibiblio.org/?m=200507
[399]: http://esr.ibiblio.org/?m=200502
[400]: http://esr.ibiblio.org/?m=200501
[401]: http://esr.ibiblio.org/?m=200412
[402]: http://esr.ibiblio.org/?m=200411
[403]: http://esr.ibiblio.org/?m=200410
[404]: http://esr.ibiblio.org/?m=200409
[405]: http://esr.ibiblio.org/?m=200402
[406]: http://esr.ibiblio.org/?m=200401
[407]: http://esr.ibiblio.org/?m=200312
[408]: http://esr.ibiblio.org/?m=200311
[409]: http://esr.ibiblio.org/?m=200310
[410]: http://esr.ibiblio.org/?m=200309
[411]: http://esr.ibiblio.org/?m=200308
[412]: http://esr.ibiblio.org/?m=200307
[413]: http://esr.ibiblio.org/?m=200306
[414]: http://esr.ibiblio.org/?m=200305
[415]: http://esr.ibiblio.org/?m=200304
[416]: http://esr.ibiblio.org/?m=200212
[417]: http://esr.ibiblio.org/?m=200211
[418]: http://esr.ibiblio.org/?m=200210
[419]: http://esr.ibiblio.org/?m=200209
[420]: http://esr.ibiblio.org/?m=200207
[421]: http://esr.ibiblio.org/?m=200206
[422]: http://esr.ibiblio.org/?m=200205
[423]: http://esr.ibiblio.org/wp-login.php
[424]: http://esr.ibiblio.org/?feed=rss2
[425]: http://esr.ibiblio.org/?feed=comments-rss2
[426]: https://wordpress.org/ "Powered by WordPress, state-of-the-art semantic personal publishing platform."
[427]: http://esr.ibiblio.org/graphics/glider.png
[428]: http://esr.ibiblio.org/graphics/ecsllogo.png
[429]: http://www.catb.org/~esr/aim/aim-off.png
[430]: http://wp-ultra.com/
[*RSS]: Really Simple Syndication