10 ms·
Dangerous Optimizations and the Loss of Causality in C and C++ (2010) [pdf]
- eru 8y agoI guess, if you want to know what your code will be doing when executed, don't use C (and don't even dream of C++). Those are reserved for people who value speed over correctness.
- tomnj 8y agoFalse. Like for any language, C and C++ programmers (should) put very high value on correctness. Incorrect code can be written in safe languages too, but clearly C/C++ make it much easier to kill your program spectacularly. Discipline, knowledge, and tools are required to work in C/C++.
- pjmlp 8y agoThe usual statement. First time I heard it was about 1993.
- charleslmunger 8y agoNot just kill your program spectacularly - in memory unsafe languages, simple logic errors turn in to remote code execution.
- hardlianotion 8y agoI think the answer is probably to try to conform to the standard, instead.
- chowells 8y agoI have a small program which uses an undefined behavior. How would you rewrite this so as to not do so, but maintain all existing defined behaviors? #include <stdio.h> int main() { int a, b, c; printf("Please enter two numbers: "); scanf("%d %d", &a, &b); c = a + b; printf("The sum of the numbers you entered is %d\n", c); return 0; } This is the problem. There is no non-trivial C code that doesn't use some undefined behavior somewhere. And it works just fine, right now. But who says it will on the next version of the compiler?
- monocasa 8y agoYou can also take the same route as sel4. They have a formal, machine readable specification of what their C code is supposed to do, and then verify that the output of the C compiler matches that specification. It's a nice 'have your cake and eat it too' situation where you can have formally verified, high assurance binaries that were compiled with gcc -O2, but with gcc removed from the trusted computing base.
- drb91 8y agosel4 is also absolutely tiny on purpose. Imagine the man hours needed to verify Firefox.
- monocasa 8y agosel4 is also the work of a very small handful of people, with a lot of the verification code hand built. A huge chunk of the work needn't be redone, just like you wouldn't need to rewrite a c compiler for every c project. So yes, they kept the verified code small, so that they could focus on all of the tooling. I'm unconvinced that formal methods intrinsically can't scale.
- bluGill 8y agoUnfortunately I'm also not sure if formal methods can scale. In large projects the area is almost completely untouched. From what I can tell those who are using it in large projects aren't talking. (safety critical and military applications both tend to be places where you don't talk about what you have done). I'm looking into proposing to management that it is a solution to our quality problems, but I don't want to look like a head in the clouds guy with no business sense. (We already have a good automated test culture, but they can only prove everything we thought of works, we have lots of issues with situations we didn't think about)
- AstralStorm 8y agoThe corollary to "not sure" is to try a few times. Almost nobody does because formal code writing forces a constraint / logic / contract thinking which is alien to many alleged programmers. It could be taught. Afterwards, compare performance and quality of the result. Could be a big competitive advantage...
- keldaris 8y agoNo, just have some basic knowledge about how your compiler works and make decisions accordingly. Every major compiler lets the programmer specify exactly the tradeoffs you want. C/C++ simply don't hold your hand by default and let you get the best (reasonably possible) performance if you so desire. That's exactly the way it should be.
- a1369209993 8y agoNo, just use a compiler that doesn't actively attempt to malicously sabotage you. C has perfecly well defined semantics for (eg) null pointer dereference: read or write memory location zero, and consequently probably crash. Not "silently rewrite the pointer to nonzero-but-still-pointing-at-address-zero-somehow and proceed to bypass subsequent sanity checks for no damn reason".
- jcelerier 8y ago> C has perfecly well defined semantics for (eg) null pointer dereference: read or write memory location zero, and consequently probably crash. ... no, C explicitely has no well defined semantics since it's undefined behaviour. You may believe that C do due to habit but that's not the case.
- a1369209993 8y agoNo, C explicitly does not define semantics; it still has them, because the underlying hardware and ABI provides them, whether the C standard likes it or not. That's the point: if the compiler isn't actively sabotaging you, you end up with the semantics of the macine code you're compiling to, and can benefit from obvious sanity checks like not mapping anything at address zero.
- pjmlp 8y agoThis is, those semantics you state as defined don't translate into portable C code, not even between compiler versions on the same platform.
- SlowRobotAhead 8y agoYes, I too believe C is "only for speed"... I suggest we both get rid of any device that uses C code and move the most remote places on earth. "C is for speed only"... Do you not realize there is an entire embedded world that runs on C?
- pjmlp 8y agoThere are alternatives to C on the embedded world, it is a matter of actually be open minded.
- SlowRobotAhead 8y agoLOL. Please, tell me what the alternatives are. I’ve only been doing commercial embedded product design for 15 years. Tell me all about how one time you saw a got for “embedded rust” or something.
- pjmlp 8y agoApparently you need to broaden your horizons. https://www.ptc.com/en/products/developer-tools/objectada https://www.ptc.com/en/products/developer-tools/objectada https://www.ghs.com/products/AdaMULTI_IDE.html https://www.ghs.com/products/AdaMULTI_IDE.html https://www.mikroe.com https://www.mikroe.com http://www.astrobe.com/default.htm http://www.astrobe.com/default.htm http://www.microej.com http://www.microej.com https://www.aicas.com/cms/ https://www.aicas.com/cms/ Just a couple of examples from many more, after all I don't want to overflow you with information.
- SlowRobotAhead 8y agoYea, I can tell you don't work in embedded and have never made anything for production.
- pjmlp 8y agoThere are many companies delivering embedded products successfully with those technologies. I call that production deployment. As for myself, feel free to believe whatever makes you feel better.
- coliveira 8y agoI don't get why people get so upset about C++ optimizations. They are by nature optional. If you think an optimization is dangerous, just disable it. That's why compilers have optimization levels, so you can select what you're comfortable with.
- keldaris 8y agoExactly. It's become fashionable to decry the lengths to which C/C++ compilers are able to go in the pursuit of performance because of "safety" issues, but the advantage of letting the programmer fully control every knob in the chain is immense.
- pjmlp 8y agoWith great power comes great responsibility. I might not code daily in C++ anymore, but it would be nice that the software I rely on, specially in devices I am not able to upgrade, wouldn't suffer from such issues. Butcher knifes are deadly sharp, yet those conscious ones do use proper gloves when handling them.
- dpc_pw 8y agoC++ is not "letting the programmer fully control every knob". Quite the opposite. Buggy, insecure, broken software is usually not the intention. The developer wanted one thing, and got something else, because of arcane details of the language. C++ is just a bad programming language, and "but it's powerful" is not invalidating that fact.
- keldaris 8y agoI certainly wouldn't call C++ a good programming language (rather, I would call it the only viable option for most of its usecases, badly designed though it is). However, I will stick by the "letting the programmer fully control every knob" phrase I used. I never claimed it makes it easy and you can make a lot of good arguments regarding better defaults, but it absolutely eschews restricting programmer freedom, at a not inconsiderable price.
- petermcneeley 8y agoThe simplest and best example in this presentation: (x * 2000) / 1000 can be reduced to x * 2 but only if we make some assumptions about x (about if x can overflow) The reason why this is such a problem in C languages is because most of the time one is working in a mixed abstraction environment. The underlying model for many parts of the language is assembly. In order to get away from these issues and to produce more optional code we should move away from mixing models of abstraction.
- andromeduck 8y agoThe value of (X2000)/1000 will always depend on type. For example, this could result in overflows if it were a fixed point integral or loss of precision if it were a floating point type. X could be a non associative type with overloaded operators like a digest/summary type. IMO the wierdist thing to read in C++ though is X / A A. Its roughly the same as X -= X % A. They values may differ if X or A are negative.
- Contero 8y ago> Consider the following example: if (cond) { A[1] = X; } else { A[0] = X; } > A total license implementation could determine that, in the absence of any undefined behavior, the condition cond must have value 0 or 1. > If undefined behavior occurred somewhere in the integer arithmetic of cond, then cond could end up evaluating to a value other than 0 or 1 I don't even follow this very first example. Neither C nor C++ have any requirement that their condition statements be given 0 or 1. In C: > the first substatement is executed if the expression compares unequal to 0. In C++: > The value of a condition that is an expression is the value of the expression, contextually converted to bool Where conversion to bool is defined as: > A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true I'm sure such a thing could occur if cond had a boolean type but contained uninitialized data. That would be similar to the situation talked about in this link: https://markshroyer.com/2012/06/c-both-true-and-false/ https://markshroyer.com/2012/06/c-both-true-and-false/
- Pinus 8y agoI, too, scratched my head over that for a while, and eventually realized that I had probably misunderstood what the authors are trying to say. I think what they mean is that if the compiler has analyzed the code, not shown in the example, that comes before the if statement, and concluded that unless something undefined happens, cond can only be 0 or 1, then it can optimize out the condition. They are not saying that the code actually shown is enough to conclude that cond must be 0 or 1.
- Contero 8y agoYeah re-reading the wording now I think you're right. It's this part that throws me off: > could determine that, in the absence of any undefined behavior "could determine that" based on the code example shown vs "could determine that" based on static analysis performed on some preceding code It would have been a lot easier to wrap my head around if it were an example where cond could be 0 or 4 or something along those lines. It would really underscore the compiler's desire to reuse the cond as the index.
- kulu2002 8y agoI had very bad experience of -O flag especially in case of ISRs. I don't use any optimisation levels... even at -O0 GCC seems to do something. Good practice as per my experience is to check MCDC and code coverage at unit test level