Rules for Developing Safety Critical Code [pdf]
pixelscommander.com
pixelscommander.com
I don't know how this works in practice, but it sounds like a great system even when dealing with code in a lower-risk setting.
I try to do this with my team as much as possible. I am limited by my superiors, who don't hold the same beliefs about maintaining morale and intrinsic motivation.
When push comes to shove, it doesn't matter who made a mistake, all that matters is that things didn't work. And that's all you really care about. The result.
People make mistakes. But systems let mistakes into production.
Which is awful.
If you have a billion dollar program where a failure will kill people and create a political storm that will get your management chain fired or sidelined, you can justify spending $100M on the process (ie lots of people + less ability) to push quality.
See: http://en.wikipedia.org/wiki/Poka-yoke
If a bug got through, and you don't test. Then obviously its because you don't test. Not because the programmer isn't superhuman, and doesn't make mistakes.
Everybody makes mistakes, design the system to handle it.
1: https://codeascraft.com/2012/05/22/blameless-postmortems/
2: http://www.amazon.com/Field-Guide-Understanding-Human-Error/...
The actions of the deceased often contribute to their death. The only lesson from assigning blame to the pilot for pilot-error is "Try not to make mistakes". Placing the system at the center of the investigation makes for better checklists that reduce the probability of pilot error for many pilots.
"Don't wear red and march in a straight line" is a better tactic than "Don't get shot."
Wow, am I ever frustrated by the summary ignoring of warnings I see going on around me. I spend my spare time at work making warnings go away and deleting uncommented @SupressWarnings from our codebase.
In a word, KISS. Another engineer designing critical systems for the US government coined that one, apparently [1].
Maybe one good exercise would be to ask programmers to write some program, and then let people vote on which code is the simplest to read and to understand.
Haven't tried Clang because I am on Windows for my C++ stuff.
1 - Some tools and libraries (like GTK - yeah) like to throw unfixable warnings. "Yeah, this platform is missing this feature so let's throw a warning"
2 - Sometimes fixing a warning results in something much more complicated than the original code. (see for example half of PyLint warnings)
So, for that to work it's important the tool warnings are good (and at least with GCC on C they usually are)
But yes, that is a huge pet peeve of mine. I have all my QT header includes wrapped with pragmas to turn off warning because otherwise they spit out endless, useless warnings.
So when you go to do a minor fix, do you also touch other code that now triggers a warning?
Or worse, they break existing code (I've seen this happen with C++ on GCC)
So while that warning can certainly be useless information, it does definitely catch bugs. Unfortunately, the people who write code like the above are also more likely to be people who ignore warnings. ;-)
#include <string.h>
struct S {
int i;
char c;
int j;
};
void f(void) {
struct S s1 = { 0, 0, 0 }, s2 = { 0, 0, 0 };
memcpy(&s1, &s2, 9);
}
int main(void) {
f();
return 0;
}
MSVC, Clang, and PC-Lint are all silent on the code (which is reasonable behavior since it's impossible to glean programmer intent from that snippet -- maybe the programmer really only wants the first nine bytes!). (Btw, yes, I am using the analyzer features for MSVC and Clang, not just relying on high warning levels.)All current compilers also have mechanisms to selectively ignore warnings via pragmas, like '#pragma GCC diagnostic ignored "-Wfoo"' in clang and GCC, which can be used to suppress instances of false positives of otherwise useful warnings.
https://gcc.gnu.org/onlinedocs/gcc/Diagnostic-Pragmas.html
http://msdn.microsoft.com/en-us/library/aa273936.aspx
IMHO not using -Werror is just inexcusable.
if (!c_assert(p >= 0) == true) { return ERROR; }
// vs
if (!c_assert(p >= 0)) { return ERROR; }
// The following makes the error condition clearer, but it goes against the convention of having a hopefully true condition as the argument to assert.
if (c_assert(p < 0)) { return ERROR; }
In your example using > or < there is not an issue because it's certain the return value is either 0 or 1. However, when checking a specific variable used as a boolean I prefer to see an explicit comparison.
if(variable)
versus
if(variable==TRUE)
I developed this preference after spending weeks on a particularly nasty bug. The bug was triggered by a corrupted int that was used as a boolean variable that passed a check because if(146134613) { kill_me_now(); } will run, even though the value had been corrupted. (of course, tracking down the source of the corruption was the real fix for that case, but there's no point in having safety checks that don't work)
Either form has the same problem since an int is used in place of a true boolean (true | false | other), but I prefer the form that makes it more explicit and noticeable.
They use error-correcting memory to combat this, but it's still better to be safe than sorry when your software controls a multimillion dollar space oasis with human beings inside who have no means of escape.
[1] http://www.statemaster.com/encyclopedia/Single_event-upset
However, in the case of safety-critical software, we don't actually follow that rule perfectly. We usually have one or more main loops that never terminates, but everything called from there does terminate.
In languages that enforce totality, like Agda (which is not suitable for most safety-critical programming), you can either selectively disable termination checking on the main function, or you can recurse over a large number. I'm partial to 99999999999999999.
The reason is also pretty sad : "Pointers are easily misused, even by experienced programmers". I don't see how an experienced programmer has more chance to misuse pointers than anything else.
Some hardware (e.g. the smaller PICs) has poor support for pointers which can make indirection cost quite a lot of instructions.
Then there's the general principle of cutting your coat according to your cloth. You don't use a generalised pointer-to-rocket-engine system because you aren't going to add more engines at runtime
Well, we might. Particularly if the vehicle you're modeling for a hardware in the loop sim isn't entirely specified at compile time.
If there is anything that pointers must be used for, then they must be used. But it is hardly controversial to say that pointers are one of the least-well understood and frequently misused aspects of low-level programming.
Uncle Bob would be very upset by this statement. He advocates a maximum of 4-5 lines per function to ensure readable code in his Clean Coders video series. Anything more, and you need to refactor into smaller functions.
Uncle Bob is preaching software engineering as engineering to the heathen masses. The JPL Standards are a sermon for the choir. Uncle Bob doesn't, so far as I know, advocate C for all critical code.
Yeah, and you end up with myriad of functions which are used once and only once and it becomes impossible to actually find code which does something useful.
I have a much harder time with "_tcscpy_s" and similar suites of functions where a single-letter typo is likely to be a different function with the same signature.
Domain-specific languages are productive; their parts combine in ways giving novel results. A list of a million verbs you can only ever use for one purpose is not a language in that sense.
You're right that you end up with a myriad of functions, may of which you only use once, but I was surprised how often I actually been finding myself reusing something. I have much more code reuse than I originally figured.
One thing that might be an issue, depending on your temper is that your code almost becomes a DSL. Programs are pretty much stringed together by this "myriad" of custom functions, that might not be useful outside this one program.
How about we stop blindly accepting whatever UB says, most of what this man says is crap, really
Source: author's website http://spinroot.com/p10/