I think perhaps you and the author have different interpretations of "consistently". You might also differ on whether "safe code" is safe just because it hasn't failed (or been reported!) yet under current inputs.
> They do it as part of a much larger safety process, that is designed to be robust against faults at all levels
So, since we seem to have moderately good success through voluntary adherence to strict guidelines, we shouldn't automate away the possibility of some of these errors entirely when possible? What are the benefits of that approach?
Edit:
I think you can safely ignore my original comment. It's obvious now that I was interpreting it oddly by conflating it with some other comments and positions in this thread. Your comment does a good job of explaining how it is possible to write safe C/C++ consistently (although I might quibble by saying that it is only achieved by ignoring portions of the languages, thus confining you to a dialect of those languages, which is a point in itself to be discussed).
I would delete the original portion, but I believe in acknowledging mistakes rather than hiding them, thus this correction.
> Get to know them, and see how safe C/C++ code is actually written!
I know them and also know that only in the context of high integrity computing are companies willing to pay for such processes, because they are cheaper than closing down the company if humans are killed due to a memory corruption error.
Good luck imposing such process in industries where human lives aren't at risk.
If companies could be sued by bad software quality, it would be another matter.
A non-networked engine control unit is super hard to hack by simple virtue of being unreachable from the internet. I bet if you run a fuzzer against your perfectly safe aviation code you'd find lots and lots of security issues. But those issues aren't important.
Those examples are interesting, specifically because history has shown us this point of view to be erroneous through those exact systems.
Automotive control units that are supposed to be segregates from certain data channels sometimes aren't. That was the cause of the Jeep remote hijacking stuff.[1] Any automation has to have some inpute and output to be useful for more than anything as a heater, and assuming your inputs aren't "networked" may not be valid given you likely can't control exactly how it will be used now or in the future.
For aviation, there have been problems with assumptions regarding the integrity of the channels used for communication between planes and the ground. This has led to certain systems being exploitable, even if not as bad as the initial hype made it sound.[2]
1: https://www.wired.com/2015/07/hackers-remotely-kill-jeep-hig...
2: https://defcon.org/images/defcon-22/dc-22-presentations/Pols...
As long as no one does something silly a decade from now when it comes to the networking on the plane/ship/factory.
Safety is a property of a system and the context in which it's used. Safety is not a property of its individual components, including its code. If your CPU's GPIOs were directly accessible through the Internet, your computer would be hacked too; does that mean your system is not safe?
Your claim that MISRA and standards for safety critical software also provide security against targeted attacks does not really follow.
ISO 26262 recognizes this, which is why different components in your car are developed to different integrity levels. No lives are lost if Firefox misrenders a JPEG, so it has a low rating permitting lax development practices.
That said, with crypto-ransomware and other cybersecurity hazards, it's well past time for software development to take some pages from the safety engineering book. STPA-Sec is one example of an attempt at this.
It is mostly generated from a model not necessarily simulink. The generated code usually have rules for the code so no global parameters, no pointers etc can be used.
Of course the modeling tools speak mostly C. This illustrates how C's weaknesses are mitigated in practice, and how much work prospective C-replacements must do to be competitive.
Except there's likely a false sense of security in how well those mitigations work. Part of the problem with C is that later optimizations by the compiler can yield insecure code at a later date because of undefined behavior and compiler optimization techniques that take advantage of it. In other words, if your generated code takes advantage of any undefined behavior, there's no guarantee that the same code compiler on the same compiler with the same flags but with a different/newer version of that compiler will yield bug free code in both cases.
Can those models produce C code with absolutely no undefined behavior? Maybe? When's the last time someone did a close look at exactly what they were generating? Did they make sure to look again when the underlying architecture changed (even from one version of ARM to another...)?
See the somewhat recent Cap'N'Proto remote vuln[1] submission for a modern case of this, and a good discussion of the problem in detail.
Effectively 90% of the dev work is done higher level by the various specification and constraint tools. All that's left to the C coder is the most menial of tasks, "dumbly" implementing the algorithm exactly as spelled out in the spec. And even then every piece of code will be checked multiple times before being validated. There's simply not enough leeway for the coder to make a significant mistake, or at least that's how it's supposed to be.
Clearly generalizing this approach to all of software development seems impractical. It's extremely costly and makes it hard to make quick changes to the codebase. For non-critical applications it's probably overkill. There's room for a compromise I think.
The problem with C IMO is that on its own it's highly and uselessly unsafe. At the time of its conception it was probably impractical to write a compiler that would check things like lifetimes statically because it would've made compile times unbearably long but nowadays it's not really a problem anymore.
Do you really encourage people to write critical code in a language where the compiler gladly compiles codes like this, without even a warning (tested with -Wall -Wextra on gcc 6.4)?
int test(void) {
int i[3] = {0};
return i[8];
}
And the following code only with a non-critical warning: int *test(void) {
int i;
return &i;
}
Isn't the entire hacker mantra to have the computer work for you? I'd prefer if my compiler was actively trying to detect my mistakes instead of dumbly spewing machine code. > int test(void) {
> int i[3] = {0};
>
> return i[8];
> }
clang will warn. gcc will warn with -Wall -O2. > int *test(void) {
> int i;
>
> return &i;
> }
You are free to use -Werror.I encourage people to learn to use their tools first. Instead of whining about the language when it is their tools that do not do what you want by default.
And I don't think -Werror is a good general purpose solution because it's too broad. Many warnings are just fine as warnings and for big projects that build on several operating systems using a lot of 3rd party libraries there's bound to be a few harmless warnings here and there. For instance the perfectly valid "if (a && b || c)" will warn with -Wall. I guess I'd want a "-Werror-on-serious-warning".
That's why sane defaults matter, if those warnings were errors to begin with they would be fixed upstream, if instead you decide unilaterally to turn on -Werror for your code then you're screwed if your third party headers weren't as stringent with their coding rules.
Right. So GCC isn't really a static analyzer. But it does the analysis that is required to perform certain optimizations, and as a side effect you also get some new warnings with the optimizations enabled.
> And I don't think -Werror is a good general purpose solution because it's too broad.
It sure is too broad for all existing software to compile, but if we're talking about security-critical software, what is with this double standard of bashing C for the lack of stringent checks per the standard and at the same time requiring compatibility with third party software that isn't built to the same standard?
I think if you're doing something security critical, then you must want the same stringent checks from all the libraries you use. Which means you choose the good libraries, or make your own, or fix the existing ones. Yes, positive encouragement from sane defaults could push other projects into doing the right thing, but as long as they don't, you really don't have to use their bad code in your security critical product. Yet, it is entirely usable. OpenBSD for instance compiles the kernel and libcrypto among other things with -Werror. Other parts of the system may be built with less stringent checks.
It is, by the way, possible to only turn specific errors into warnings with -Werror=... Likewise, you can disable specific annoying warnings.
I agree that it would be nice if compilers provided sane set of warnings (and errors) out of the box without any extra tweaking. I think we're getting closer and closer thanks to clang pushing things in that direction. On the other hand, I don't suppose people will ever agree which warnings are the right ones. I'd say most people who want stringent checks will enable -Wall and -Werror, and they will add the parentheses in the expression you mentioned, even if it is completely legit without them.
The problem I have with this is the assumption that software you write that may be used by others can easily be classified into security-critical software and non-security-critical software. Sometimes you don't know, sometimes it changes ten years later as something gets pulled in and used because it's easier, multiple times over the years until the original author of a portion of the code may be entirely unknown, much less their intention for whether it was sufficiently robust for security critical situations (think an OSS library that may have forked a few times, and copied small bits of code such as utility functions from some other projects).
It's time to switch to safety by default. We should fail safe, and require flags to allow previously failing code to compile, not to just hear that it might cause a problem.
Apart from that, don't assume flags and static analyzers can save you. If you're building something security critical, you do not make any assumptions about the code you depend on. You don't assume it is in some class. You don't "don't know", you vet the code. Flags and analyzers, default or not, are at best going to save you from a small subset of problems. The code might still be completely backwards and insecure.
1: https://www.wired.com/2015/07/hackers-remotely-kill-jeep-hig...
2: https://defcon.org/images/defcon-22/dc-22-presentations/Pols...
With respect, two mistaken beliefs:
1: Only a few programmers can write safe code.
2: One will naturally encounter such programmers in the course of a prestigious career working for a high-profile web browser company.
But mediocre programmers consistently write safe C/C++ code, every day. They do it in the context of aviation, automotive, etc. They do it as part of a much larger safety process, that is designed to be robust against faults at all levels, from design through development through manufacturing through end-user servicing. Software development is but one facet, and compliance to MISRA, ISO 26262, etc is only the start.
Get to know them, and see how safe C/C++ code is actually written!