Slashdot Mirror


Overeager Compilers Can Open Security Holes In Your Code

jfruh writes: "Creators of compilers are in an arms race to improve performance. But according to a presentation at this week's annual USENIX conference, those performance boosts can undermine your code's security. For instance, a compiler might find a subroutine that checks a huge bound of memory beyond what's allocated to the program, decide it's an error, and eliminate it from the compiled machine code — even though it's a necessary defense against buffer overflow attacks."

199 comments

  1. old news from decades ago by iggymanz · · Score: 4, Insightful

    well known for decades that optimizing compilers can produce bugs, security holes, code that doesn't work at all, etc.

    1. Re:old news from decades ago by NoNonAlphaCharsHere · · Score: 5, Insightful

      That's why I always use a pessimizing compiler.

    2. Re:old news from decades ago by iggymanz · · Score: 1

      ah, disgruntled and curmudgeonly old coot hand writing assembly from pseudo-code outline. Yeah, done that

    3. Re:old news from decades ago by sinij · · Score: 1

      Make sure to run it on DVL distro

    4. Re:old news from decades ago by KiloByte · · Score: 5, Insightful

      Or rather, that optimizing compilers can expose bugs in buggy code that weren't revealed by naive translation.

      --
      The creatures outside looked from Alt-Right to Antifa; but already it was impossible to say which was which.
    5. Re:old news from decades ago by Kaenneth · · Score: 1

      *cough* Microsoft .net

    6. Re:old news from decades ago by Marillion · · Score: 4, Insightful

      Right. The other part of the issue is why didn't anyone write a test to verify that the buffer overflow detection code actually detects when you overflow buffers?

      --
      This is a boring sig
    7. Re:old news from decades ago by AuMatar · · Score: 3, Insightful

      Because it worked in debug mode (which generally has optimizations off)?
      Because it was tested on a compiler without this bug? The people writing the memory library is usually not the people writing the app that uses it.
      Similarly, it was tested on the same compiler, but with different compiler flags?
      Because that optimization didn't exist in the version of the compiler it was tested on?
      Because the test app had some code that made the compiler decide not to apply the optimzation?
      Life is messy. Testing doesn't catch everything.

      --
      I still have more fans than freaks. WTF is wrong with you people?
    8. Re:old news from decades ago by blackwizard · · Score: 2

      I'm going with old news from decades ago.

    9. Re:old news from decades ago by K.+S.+Kyosuke · · Score: 0

      The other other part of the issue is why the hell aren't we programming en masse in safe languages in which the compiler adds its own checks (rather than removing yours)?

      --
      Ezekiel 23:20
    10. Re:old news from decades ago by itzly · · Score: 3, Interesting

      That's an example of a programmer not understanding the rules of a conforming C/C++ compiler. It should be fixed in the source, not in the compiler.

    11. Re:old news from decades ago by UnknownSoldier · · Score: 1

      Because of TINSTAAFL.

      Just because you want extra safety checks around _your_ code does not imply that I can afford the performance _penalty_.

      C is a mid level language because it tries to have zero over-head. If you want extra checking done YOU tell the compiler you explicitly so that it doesn't effect everyone's run time performance implicitly.

      While I agree it would be extremely useful to be ability to have "safe arrays", and even tag data with "volatile" to tell the compiler "Hey this is important due to security optimizations" we don't have that.

    12. Re:old news from decades ago by tepples · · Score: 2

      Perhaps the problem is that standard C isn't expressive enough to express some operations that some programs require, especially with respect to detection of integer arithmetic overflows.

    13. Re:old news from decades ago by K.+S.+Kyosuke · · Score: 3, Interesting

      I'd personally rather work in languages that are safe by default with optional (but available) extra performance/lower safety where explicitly instructed (the way Common Lisp does it, for example), rather than the other way around. I've come to the impression that most codebases would have fewer overrides in the former case rather than the latter. If you think the latter is preferable, what about all those bugs and security vulnerabilities we got "thanks" to that approach? Was it actually worth it?

      --
      Ezekiel 23:20
    14. Re:old news from decades ago by dreamchaser · · Score: 1

      I've always preferred inline assembly or linked asm routines for tricky bits, but the problem then is it's not portable.

    15. Re:old news from decades ago by Anonymous Coward · · Score: 0

      You can build a safe library on top of a fast zero overhead one. You can't build a fast zero overhead library on top of a safe one.

    16. Re:old news from decades ago by Anonymous Coward · · Score: 0

      The Algol machines of Burroughs were apparently much better than the C crapola we have now.

      So The Powers made C-based crap dominate the world of computing. Now have a cheap joke on military intelligence while they laugh all the way to Ft Meade.

    17. Re:old news from decades ago by Anonymous Coward · · Score: 0

      The penalty is very much overblown and can be limited to less than about 10% of runtime. Government does not like secure code - this is the key reason for C being popular. They made sure.

      Algol, Ada, Pascal - all way too secure.

    18. Re:old news from decades ago by russotto · · Score: 2

      Perhaps the problem is that standard C isn't expressive enough to express some operations that some programs require, especially with respect to detection of integer arithmetic overflows.

      Indeed; the compiler's even allowed to assume signed integer overflow doesn't happen, which is where you get into trouble. Yet we have this perfectly good mechanism for detecting integer overflow (condition codes) and no way to reach them from high level languages (C isn't unique in this respect)

    19. Re:old news from decades ago by lgw · · Score: 2

      If you're testing only in debug mode, you're doing it wrong. Do your customers run debug? No? Then all your tests must run retail or you fail.

      Is this a compiler bug? Doubtful. Chances are it's code that isn't standard that was getting away with its non-standard behavior until the compiler started enforcing this bit.

      Compiler flags? Again, test the binaries your users will run.

      Testing can catch a lot, if not half-assed.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    20. Re:old news from decades ago by K.+S.+Kyosuke · · Score: 1

      When considering libraries, you're very much correct. When considering languages, interestingly, the situation is very much the opposite.

      --
      Ezekiel 23:20
    21. Re:old news from decades ago by gweihir · · Score: 2

      That would be, you know, sane? And competent? Cannot have that in somebody that does software...

      There are also nice compiler directives that are used to switch off optimization for some functions.

      --
      Most ACs are not even worth the keystrokes to insult them. Be generically insulted by this and ignored otherwise.
    22. Re:old news from decades ago by Anonymous Coward · · Score: 0

      False.

      Only faulty compilers do what you just outlined above. Optimising compilers make transformations on code based on proofs that the two have equal semantics.

      The problem that this article raises is that programmers often rely on behaviour that is undefined in the language spec, and that all undefined behaviours are equal in the eyes of the compiler.

      The bugs here are very much in the program source (for relying on undefined behaviours), and nothing to do with optimising compilers.

    23. Re:old news from decades ago by AuMatar · · Score: 1

      And if you're writing a library, you don't know what compiler much less what flags the user will use. Are you willing to pay several thousand dollars for seats for obscure compilers?

      Yeah, you're an idiot.

      --
      I still have more fans than freaks. WTF is wrong with you people?
    24. Re:old news from decades ago by Darinbob · · Score: 1

      Though technically the compiler would be incorrect by removing "unnecessary" code when it actually is necessary. The thing is, if the compiler is good enough to detect that the code is checking out of bounds when it doesn't need to, then the compiler was able to logically infer that it was impossible to write code out of bounds, which means it should be good enough to print out a warning when the code does have possibility of buffer overlows.

      The examples given in the articles listed are things that I would expect a smart compiler to give warnings about, and it would be a dumb compiler that optimizes the code away through over eager optimization (too smart for its own good). After all, this code uses undefined behavior and this tool being discussed finds these cases by hunting down undefined behavior, and undefined behavior should always warrant a warning.

      If the compiler has enough information to think it can optimize the code away, then it also has enough information to issue a big ugly warning.

      The problem here isn't over-eager compilers but over-eager compiler writers.

    25. Re:old news from decades ago by Darinbob · · Score: 1

      Which is where a compiler should actually issue a warning. Then the programmer, if deciding the code really is necessary that way, adds some pragmas, attributes, or typecasts, and then double checks the compiler output afterwards. I agree though that such cases are sometimes very useful, however a compiler must never optimize this code away silently.

    26. Re:old news from decades ago by swillden · · Score: 1

      Provide a test suite along with the library. Users may or may not bother to run it, but at least then it's on them.

      --
      Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
    27. Re:old news from decades ago by Euler · · Score: 1

      I don't think any language is portable at that level, so you may as well use asm (my preference is linked instead of inline to ensure a clean and simple abstraction.) Every processor has different math status registers and different math instruction capabilities. I'm not sure how C can express these things.

    28. Re:old news from decades ago by Euler · · Score: 1

      Your statement is perfectly true.

      Unfortunately, faulty compilers are more than just hypothetical. But besides that...

      Even with a perfect compiler, the knowledge it takes to avoid these 'equal semantics' traps is beyond most experienced programmers (no matter how much our egos say otherwise.) But otherwise, I totally agree that most 'optimizer bugs' I've seen are just lack of understanding by the programmer. The compiler rightfully saw its solution as equivalent to what the source code stated.

      I think there should be a rule of thumb: "Every year of programming experience gets you halfway closer to knowing all the gotchas"

      So we can blame the programmer, but that isn't going to produce better code in the real world. The tools and languages need to meet with common expectations. If that means taking a more "secure by default" approach then so be it. The experts can choose to take off the training wheels with pragmas or additional compiler options.

    29. Re:old news from decades ago by sjames · · Score: 1

      Arguably, it's a bug in the standard. It defies the principle of least astonishment for a procedural language.

    30. Re:old news from decades ago by Anonymous Coward · · Score: 0

      Try IBM Mainframe compile options - there are *heaps* of options, including range/bounds checking and now Metal options, ranging from noopt opy(none) to opt(everthing + kitchen sink). Now because IBM always had storage pools, and extra bits to control memory allocations, it is very,very hard to cause 'memory leaks' . All this and more, before 'data execution bit' was re-invented.

      IF these options existed in PC land, most of the security flaws would have been found years ago - if they wanted to.
      For really tight compilers, try some of the old fortran and Japanese compilers. On the mainframe, the programmer is in total control, and always will be.

    31. Re:old news from decades ago by Anonymous Coward · · Score: 0

      I'd personally rather work in languages that are safe by default with optional (but available) extra performance/lower safety where explicitly instructed (the way Common Lisp does it, for example), rather than the other way around.

      Works well enough where software and hardware are bought independently.
      In the case of embedded device using a language like that would lead to the need of microcontroller both with more program space and faster clock speed. This will in turn mean that the device will be larger and more expensive without actually performing more compared to the competition. (And it will have shorter battery time is it applies.)

    32. Re:old news from decades ago by StripedCow · · Score: 1

      This is assuming you can write 100% bug-free code. You can't, for any realistically sized project.

      --
      If Pandora's box is destined to be opened, *I* want to be the one to open it.
    33. Re:old news from decades ago by careysub · · Score: 1

      TINSTAAFL? Mixing idioms much?

      The famous phrase (quite deliberately using a non-mainstream dialect) is "there ain't no such thing as a free lunch": TANSTAAFL,

      If you wish to recast it in a standard idiom (for reasons I cannot divine) then you should go with "there isn't any such thing as a free lucnh": TIASTAAFL. But this is pure pedantry.

      --
      Starships were meant to fly, Hands up and touch the sky - Nicky Minaj
    34. Re:old news from decades ago by Anonymous Coward · · Score: 0

      Arguably, it's a bug in the standard. It defies the principle of least astonishment for a procedural language.

      If you're astonished by standard-conforming behavior, you're in over your head as a programmer.

    35. Re:old news from decades ago by sjames · · Score: 1

      If you don't understand that it is the standard itself where the astonishment occurs, you are over your head in this discussion.

    36. Re:old news from decades ago by en.ABCD · · Score: 1

      I assumed that "TINSTAAFL" was "There Is No Such Thing As A Free Lunch", which also is in standard idiom and requires less changes from the original (deliberately non-standard) version from RAH.

    37. Re:old news from decades ago by lgw · · Score: 1

      If you're writing a library that messes around in the dark corners of C, you should know exactly what you're doing WRT the standard. And what oddball compilers are still in use in an environment where people are consuming open source libraries? Obviously, you want to cover GCC, clang/llvm, VS, and maybe Intel yourself. For the rest, as the sibling post says, libraries should come with unit tests in the modern world,

      --
      Socialism: a lie told by totalitarians and believed by fools.
    38. Re:old news from decades ago by AuMatar · · Score: 1

      Most of the embedded world? The embedded world heavily uses compilers like RVDS. And nobody is going to bother running the unit tests. In addition, its damn hard to write unit tests that test something that should fail in a stack dump.

      --
      I still have more fans than freaks. WTF is wrong with you people?
    39. Re:old news from decades ago by david_thornley · · Score: 1

      That's an OLD problem. When I was using FORTRAN 66, I had to put a sentinel card at the end of the data I was reading. (Actually, I usually used a nonstandard extension.) The OS knew when my data was all read, but there was no standard way to let FORTRAN know.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    40. Re:old news from decades ago by UnknownSoldier · · Score: 1

      ain't is not proper English

      How about focusing on the actual issue instead pointless pedantic non-issues please.

    41. Re:old news from decades ago by david_thornley · · Score: 1

      The big problem is the extent of undefined behavior. Undefined signed integer overflow made a great deal of sense when C was being designed: some computers would fault on arithmetic overflow, while some would wrap around, and specifying one behavior would have made C run badly on a computer doing the other. (In retrospect, calling it "implementation-defined" would have worked better.) Probably the best use for "unsigned" in C and C++ is to avoid arithmetic overflow, since that's completely defined by the standard.

      There's other undefined behavior, and some of it isn't easy to tell. Consider "i = j++;", which is perfectly good, unlike "i = i++;", which is undefined. If we put in a layer of indirection, we've got "(*i) = (*j)++;", which is defined as long as i is not the same as j, and in the general case it's undecidable whether that can happen or not. I think it'd be useless for a compiler to point out every situation in which undefined behavior might happen.

      Also, the optimizer is going to be working on a program that's considerably transformed from the source at times, and if it encounters undefined behavior it's going to be hard to associate it with a source code line.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    42. Re:old news from decades ago by david_thornley · · Score: 1

      You can write a safe library by adding provably correct constructs to a zero-overhead one. You can write bug-free code for small pieces of code, and you can combine these pieces to get code that almost certainly has bugs but is known not to have certain specific bugs.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    43. Re:old news from decades ago by dgatwood · · Score: 1

      Indeed; the compiler's even allowed to assume signed integer overflow doesn't happen, which is where you get into trouble.

      Translation: In their attempt to make the spec as portable as possible, they gave compiler writers too much freedom. Honestly, the first time I heard about this problem... maybe a decade ago... my immediate reaction was, "Why don't they just change the spec to say that those optimizations aren't allowed?"

      I still maintain that tightening the C spec is the correct fix, and that all the monkeying around with checking to see if the computation would overflow by subtracting one operand from or dividing one operand into INT_MAX and comparing the result against the other operand is just silly. After all, a sufficiently smart compiler, given the assumption that integer overflows are impossible, should optimize out those pre-tests anyway, by virtue of the fact that you're about to add them, and integer overflows are impossible. And it wastes a tremendous number of CPU cycles doing throwaway computation for no reason other than working around the C spec being utterly and completely brain damaged.

      --

      Check out my sci-fi/humor trilogy at PatriotsBooks.

    44. Re:old news from decades ago by lgw · · Score: 1

      And nobody is going to bother running the unit tests

      Wow, the spirit of the 1980s is alive and well I see. No code reviews either, I bet. It compiles, ship it!

      But for overflow checking, like memory leaks, there are good tools for most environments, as well as static analysis tools that can warn you of likely-problematic nonstandard code. The tests in TFA seem oddly-intentioned.

      If you're worried about someone diddling the stack, put sentinels on both ends of every important object and check them on every important function call. We did that when I did appliance development: the first time in every function that time you dereference a pointer to an interesting object, you check a marker at the end (one that's cleared on free, so you catch freed objects) and generation number at the front (to ensure the object wasn't freed and re-used, becoming a different instance than the caller thinks it is). While that helped with security, it helped immensely with debugging. Those object lifetime bugs where an object gets improperly freed, but the memory is re-used for the same class of object (as is normal with slab allocation) are just too insidious without such checks.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    45. Re:old news from decades ago by russotto · · Score: 1

      After all, a sufficiently smart compiler, given the assumption that integer overflows are impossible, should optimize out those pre-tests anyway, by virtue of the fact that you're about to add them, and integer overflows are impossible.

      Fortunately, that particular optimization is not allowed. Maybe we need a construct which catches overflows, something like ifoverflow(arith_expr) {...} else {...} If any overflow occurs within the protected expression, any assignments made are set to implementation-defined (not undefined) values. ifoverflow(c = a+b) {

    46. Re:old news from decades ago by sjames · · Score: 1

      The particular issue had nothing to do with undefined behavior. Check the issue again. The compiler elided a well defined explicit and non-conditional call to memset before returning from the function. It is no longer executing the program as written.

      A sane spec would allow it to issue a warning that the code appears to have no effect (it would be wrong, but at least no harm done). So long as an override is made available, it could fail the compilation if -Werror is set.

      One might expect a high level language, especially a functional language, to take liberties like that, but C is a mid-level imperative language (or at least it's supposed to be). Of course a high level and/or functional language would never allow reading uninitialized memory so it wouldn't be a problem.

      The case of i = i++ is somewhat ambiguous at the syntactic/semantic level. You are effectively asking it to alter the value of i twice. since the ++ postfix implies an immediate increment after access, arguably it is always ineffective (fetch, immediate increment, store). However, (and also arguably) It could be interpreted as fetch, store, increment before the next fetch which would be quite a mess in a more complex case like i = 25 + i++ where potentially the 25 could disappear.

      To contrast both, a case where optimizing is always permissible (except in the case of volatile). i = ++i+j. In that case, we end up with fetch i, increment the register, store back, add immediate 25, store to i. The store back instruction can be elided every time and the final store can be delayed if further operations on i will take place.

    47. Re:old news from decades ago by Anonymous Coward · · Score: 0

      This is why you use inline asm for such things as the compiler cannot optimize inline asm. well at lest they could not in the past, the might be able to now.

    48. Re:old news from decades ago by AuMatar · · Score: 1

      Running unit tests on a third party library? Get real. Either you trust the people who wrote it ran them, or you don't use the library. Do you run the unit tests on every library you download? Have you ever run the unit tests on a library you've downloaded? Hell, unless its all one download they aren't even downloaded, much less run. Welcome to the real world.

      --
      I still have more fans than freaks. WTF is wrong with you people?
    49. Re:old news from decades ago by lgw · · Score: 1

      In the environment I'm currently in, nothing gets checked in without unit tests. Doesn't matter who wrote it. And you bet they're run on every build, or what's the point? But we don't like to half-ass software development - easier (and cheaper!) in the long run to have quality.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    50. Re:old news from decades ago by Anonymous Coward · · Score: 0

      Yes they're called compiler bugs and are why there has been more than one compiler ever written and more than one version of those ever released.

    51. Re:old news from decades ago by Wootery · · Score: 1

      GCC is giving memset special treatment, right? If GCC didn't know whether memset would side-effect, it wouldn't elide the call. One could presumably work-around this problem by creating a static library defining memset_secure, which just called memset. When calling memset_secure, GCC wouldn't know whether it side-effects, and so wouldn't elide the call.

      (Unless you're allowing link-time optimisation. You'd have to be sure your memset_secure static-library was a real machine-code static library.)

      Aside: in the D programming language, it is possible to express 'purity' of a function, and so enable this kind of function elision for arbitrary functions.

    52. Re:old news from decades ago by idkk · · Score: 1

      As an even more pedantic aside: the word "ain't" IS proper English - but not necessarily in the dialect or register that you are currently using. For example, in mid to late Victorian England (1860 to 1900, and the country from which English comes, and to which standards on English, per se, must be referred) the word "ain't" was used in normal conversation by cultured and educated speakers, without any hint of impropriety. The arbitrary strictures that now affect "ain't", but not "don't" or "won't" or "isn't", were applied later.

      And I ain't wrong.

      --
      Ian D. K. Kelly

      idkk Consultancy Ltd.

      "Quality through Thought"

    53. Re:old news from decades ago by UnknownSoldier · · Score: 1

      If you pay more attention to history instead of criticizing others for your own lack of it, you would discover ...

      * The standard usages are: TNSTAAFL, TANSTAAFL, and TINSTAAFL

      * TANSTAAFL was first used in 23 November 1854, in "Wide West"
      * TINSTAAFL was used in 1952 by Professor Alvin Hansen in the journal "Ethics."
      * TANSTAAFL was again used in 1966 by Robert Heinlein's novel "The Moon is a Harsh Mistress."
      * TNSTAAFL is attributed to the economist Milton Friedman in 1975

      References:

        * http://en.wiktionary.org/wiki/...
        * http://en.wikipedia.org/wiki/T...
        * http://www.nytimes.com/2001/02...
      * http://mahalanobis.twoday.net/...

    54. Re:old news from decades ago by david_thornley · · Score: 1

      Yes, that. What comes immediately to mind is to create a few security functions and compile them into a library, preferably static. That way, the compiler won't know if it can elide the memset_really() function, so it won't, and in compiling memset_really() it will have to assume that the function results will be relevant. This is, of course, lame, a bit awkward, and is fighting the language rather than working with it, but I think it would reliably work.

      The other thing that comes to mind is that (in C++, at least) a cast from "char" to "volatile char" should work (you can add cv-qualifiers), and zeroing out volatile memory will work as expected.

      As far as the double alteration expressions go, those are undefined according to the C and C++ standards. (At least C++03; the evaluation rules were somewhat changed in C++11. When I asked about that on Stack Overflow, the answers were pretty much exclusively that the old rules worked just fine, and that relying on the newer rules was going to be tricky and not worth it.) Note that the order of evaluation rules govern the calculation of the result, not when any side effects are applied.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    55. Re:old news from decades ago by q4Fry · · Score: 1

      For any who do not know it (and a reminder to those who do): The Story of Mel

    56. Re:old news from decades ago by sjames · · Score: 1

      Yes. The double assignment being undefined is proper because the statements are ambiguous at the semantic level. I would say the best policy is to stay far away from it. It should be considered at least a warning condition. Eliding the memset is inexcusable in a sane spec because there was no ambiguity.

      There are a few ways to trick the compiler into doing the right thing, but it's a shame it has to be done that way. But given the importance, there should at least be a really_memset or a securely_memset available in hopes of giving the programmer some chance to get the proper behavior.

    57. Re:old news from decades ago by sjames · · Score: 1

      I'm not absolutely sure how it is coming to it's conclusions, but I *THINK* rather than being special treatment, it sees that memset itself only affects the allocated memory passed to it in pointers and it knows that that memory in this case is on the stack and will be freed when the calling function returns, so it concludes there are no side-effects and elides the call. In theory, casting the pointer to volatile should force the compiler to leave the call in.

    58. Re:old news from decades ago by Wootery · · Score: 1

      Right, which is special treatment. The compiler 'knows' that memset is what D calls a 'pure function'. If memset were just an arbitrary function, about which nothing else was known, it would not be possible to elide the call, as this might eliminate side-effects.

      Perhaps though memset is an inline function and the compiler is able to figure out its 'purity' rather than having it listed specially.

    59. Re:old news from decades ago by sjames · · Score: 1

      But memset is not pure in the general case where it might write to memory referenced by a global pointer or a pointer passed in to the calling function.

      But it likely is inline. Especially since the code to implement it is smaller than the code to set up a call.

      I know gcc has a great many declarable attributes for functions these days. Perhaps one of those was (mis-)used.

    60. Re:old news from decades ago by Wootery · · Score: 1

      In D's definition of a pure function, that's still pure.

      Pure functions are functions which cannot access global or static, mutable state save through their arguments.

    61. Re:old news from decades ago by dgatwood · · Score: 1

      Just as long as by "implementation-defined", you mean NaN and not, for example, 0. :)

      --

      Check out my sci-fi/humor trilogy at PatriotsBooks.

    62. Re:old news from decades ago by sjames · · Score: 1

      That is a more restricted definition. You need a stricter definition to safely elide code.

      Apparently the D compiler does perform further analysis to see if that stricter definition is met. See here. It seems to check if the function can modify it's arguments (for example, by zeroing them).

    63. Re:old news from decades ago by Wootery · · Score: 1

      That is a more restricted definition. You need a stricter definition to safely elide code.

      You're right. Now that I look at the 'concession to practicality' section, it's clear that purity and non-escaping arguments aren't enough to guarantee safe elision.

      It seems to check if the function can modify it's arguments (for example, by zeroing them).

      I don't get you. A pure function is allowed to perform mutation via reference-type (or pointer-type) arguments.

    64. Re:old news from decades ago by sjames · · Score: 1

      It's from the documentation. I presume/guess it means you may declare the function pure in the limited sense and that allows the compiler to check to see if the stricter definition might also apply.

    65. Re:old news from decades ago by Wootery · · Score: 1

      I presume the compiler makes those checks whenever it can. The 'purity' scheme is really about helping the programmer, not the compiler, of course.

  2. Unsable Code, again by Anonymous Coward · · Score: 5, Informative

    This is just as poorly written up as last time. These are truly bugs in the programs using undefined parts of the language. It's silly to blame the compiler.

    1. Re:Unsable Code, again by Anonymous Coward · · Score: 1

      At least then the summary didn't contain this turd:

      For instance, a compiler might find a subroutine that checks a huge bound of memory beyond what's allocated to the program, decide it's an error, and eliminate it from the compiled machine code

      Which is wrong and not even in the article. Jfruh probably heard something about overflow semantics, didn't understand a word of it, and then made something up.

    2. Re:Unsable Code, again by david_thornley · · Score: 2

      Actually, that makes sense.

      Suppose we want to check for buffer overflows in C++, so we allocate a stretch of memory beyond the buffer, zero it out, and check it to see if it's zeros later. Depending on how the buffer is used, it may be that a buffer overflow would require undefined behavior, such as accessing memory beyond the limits of a data structure. An optimizing compiler might figure that out. In event of undefined behavior, anything the compiler does is conforming, and in event of no undefined behavior the stretch of memory will remain zeros, so in either case the check for zeros is unnecessary for a program, and the compiler can remove it by the "as-if" rule.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    3. Re:Unsable Code, again by Anonymous Coward · · Score: 1

      i see this as very simplistic thinking. if the c standard were still 20 pages or so, i would agree with you. but the amount of undefined behavior is just nuts. and the compilers just laugh. they don't always issue diagnostics when optimization removes code. no! that would make life easy, and clearly programming is a man's sport.

      tl;dr. checking for overflow is valid, and the standard's writers were not considering all the possibilities when they undefined such behavior.

    4. Re:Unsable Code, again by Nutria · · Score: 1

      stretch of memory beyond the buffer, zero it out, and check it to see if it's zeros later.

      I don't remember the correct term for such regions, but nulls are a very bad sequence to put there, since... they can't be distinguished from actual, purposeful zeros.

      Better to initialize the area with something like 0xDEADBEEF.

      --
      "I don't know, therefore Aliens" Wafflebox1
    5. Re:Unsable Code, again by Anonymous Coward · · Score: 1

      Canaries.

    6. Re:Unsable Code, again by lgw · · Score: 2

      Compilers remove vastly more code than you seem to think, when optimizing. They always have - this isn't new. You wouldn't want all that spam as warnings, for sure (if you build with warnings as error, as one ought to do, you'd never build anything).

      --
      Socialism: a lie told by totalitarians and believed by fools.
    7. Re:Unsable Code, again by Darinbob · · Score: 1

      I blame both. When a compiler discovers code with undefined behavior in the language, then the compiler should issue a warning rather than taking it as an opportunity to silently perform some other optimizations. In other words, the compiler KNOWS the code is faulty, and it can't perform the extra optimizations without first knowing this. Thus I absolutely blame the compiler writers here.

      Ie, if the compiler sees "y = 0; z = x / y;" then it should warn about division by zero. Instead if the compiler thinks that this is a useless operation because division by zero is undefined and then silently removes the division from the compiled output, then the compiler is absolutely wrong and needs to be fixed.

    8. Re:Unsable Code, again by david_thornley · · Score: 1

      How about when the computer sees "z = x / y;"? Should the compiler warn of possible undefined behavior if it can't prove that y can't be zero?

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    9. Re:Unsable Code, again by Anonymous Coward · · Score: 0

      Garbage in, garbage out. What did you expect?

      The new thing (noticeable starting with e.g. gcc-4.8) is that the optimizer removes large blocks of codes because one instruction has undefined behaviour or whole loops because one iteration has undefined behaviour and the compiler has become smarted in detecting undefined behaviour. That has a multiplication effect. Since on undefined behaviour anything can happen the compiler is certainly correct removing the code. But that usually isn't the right thing to do for the user. The right thing to do is insert code that crashes on undefined behaviour so the problem gets noticed loudly.

      But there is one thing not mentioned. Even with perfectly valid code an optimizing compiler can open security holes in your code. Specifically it can cause vulnerabilities to timing attacks. The idea here is that you look for code like this:

      if (condition) { x = do_something_that_takes_long(); } else { x = do_something_fast(); }

      If you can measure how long it takes accurately enough you can figure out what condition was and thereby gain secret knowledge. So you have to write the code like this:

      t1 = do_something_that_takes_long(); t2 = do_something_fast(); if (condition) { x = t1; } else { x = t2; }

      But hey, the compiler is smart. It sees that if condition is false then t1 is never used and the calculation has no side effect so it optimized the code right back to what we had before. And it is right, that way it is faster, more optimized. So you thought you just fixed a timing attack (or thought you never had one) and the optimizer puts it right back (or generates it in the first place).

  3. UNISEX conference by Mdk754 · · Score: 5, Funny
    Wow, you know you're ready to go home when it's Friday afternoon and you read:

    But according to a presentation at this week's annual UNISEX conference

    1. Re:UNISEX conference by smittyoneeach · · Score: 1

      Where "Overage" compilers go to be seen.

      --
      Get thee glass eyes, and, like a scurvy politician, seem to see things thou dost not.--King Lear
    2. Re:UNISEX conference by PPH · · Score: 1

      I was wondering why my compiler was generating warnings about traps. I thought it meant something about catching buffer overflow conditions.

      --
      Have gnu, will travel.
    3. Re:UNISEX conference by OakDragon · · Score: 1

      So do overeager compilers suffer from premature optimization?

    4. Re:UNISEX conference by K.+S.+Kyosuke · · Score: 1

      Did you just type that on your Unicomp keyboard attached to your Univac?

      --
      Ezekiel 23:20
    5. Re:UNISEX conference by Darinbob · · Score: 1

      Hang on, this compilation is going to be great! I'm so excited! Let me just start parsing those header files, and... Oh, we're done. Apparently I've optimized away almost all your code. Thank you and good night.

  4. Complete nonsense.... by Anonymous Coward · · Score: 3, Insightful

    Any code removal by the compiler can be prevented by correctly
    coding the code with volatile (in C) or its equivalent.

    1. Re:Complete nonsense.... by Anonymous Coward · · Score: 2, Informative

      Except not, so now we have explicit_bzero()

    2. Re:Complete nonsense.... by vux984 · · Score: 1, Insightful

      Any code removal by the compiler can be prevented by correctly coding the code with volatile (in C) or its equivalent.

      Knowing that the code will be removed by the compiler is paramount to using the volatile keyword.

      That requires knowing a lot more about what the compiler is going to do then one should presume. The developer should not have to have foreknowledge of what compiler optimizations someone might enable in the future, especially as those optimizations might not even be known in the present.

      The normal use case for 'volatile' is to tell the compiler that you know and expect the memory will be modified externally; and beyond that you don't really need to know exactly what the compiler does. As the developer reasonably knows that the memory is supposed to be modified externally, it is not unreasonable that he mark it as such.

      Most security related vulnerabilities arising from compiler optimization tend to revolve around the idea that you are defending against memory being modified externally that should not normally be modified or read from externally. But that is the DEFAULT assumption for all memory.

      If you do not expect the memory to be written to or read from, you don't mark it volatile.

      So now you are saying, well, if you REALLY don't expect the memory to written to or read from externally, then you should mark it volatile.

      So... that has us marking everything volatile that we know will be modified or read from externally, and also everything that we know should NOT be modified or read from externally... so clearly we should mark everything volatile all the time... because pretty much all memory is either "supposed to be read and written to externally" or "not supposed to be read and written to externally" and the only situation where its safe not to use volatile then is when you don't care if its read or written to externally because you KNOW that it can't cause a bug or expose a vulnerability.

      I can't offhand think of many situations where I could say with any degree of certainty that if something read or wrote to memory externally that it wouldn't matter, and it would rarely be the best use of my time to try an establish it... so really... mark everything volatile all the time.

      Clearly THAT isn't right.

    3. Re:Complete nonsense.... by NoNonAlphaCharsHere · · Score: 1

      volatile is a storage class, meaning that something else (i.e. another process) might modify the memory location, meaning the compiler shouldn't remove reads even though it knows that you haven't modified it since it was last read and there might still be copy left lying about in a register. Even if you apply it to the buffer, it doesn't mean that the compiler can't decide that memory you didn't allocate doesn't belong to you anyways and remove the check. Additionally, volatile typically applies to single locations and not to whole buffers.

    4. Re:Complete nonsense.... by Threni · · Score: 2

      ---
      I can't offhand think of many situations where I could say with any degree of certainty that if something read or wrote to memory externally that it wouldn't matter, and it would rarely be the best use of my time to try an establish it... so really... mark everything volatile all the time.

      Clearly THAT isn't right.
      ---

      Yeah, that would be a poor design. You use volatile when you need to. That's the rule. You just need to work out when you need to.

      > If you do not expect the memory to be written to or read from, you don't mark it
      > volatile.

      > So now you are saying, well, if you REALLY don't expect the memory to written
      > to or read from externally, then you should mark it volatile.

      I'm not sure you typed that in right, or maybe you don't understand what volatile means or when to use it.

    5. Re:Complete nonsense.... by Threni · · Score: 1

      Yes. The example I remember - because it was when I learnt about it - was on the Amiga, where you had a memory location which was where the mouse hardware buttons were mapped into. Some compilers would see you reading it, then reading it again later and would go "ah! that location hasn't changed in between so I'll store the state of the left mouse button somewhere (register, some other memory location - doesn't matter, it's up to the compiler how it does it's stuff) and present it to the user a little bit later on". Obviously the mouse button may have changed state between the first and the second state.

    6. Re:Complete nonsense.... by david_thornley · · Score: 1

      Except that "volatile" means that the memory might be accessed through methods other than the program, which is the exact sort of thing we want to test for. In C++, "volatile" means that all memory accesses must be performed in the given order, and in proper order with other volatile memory accesses and calls to I/O routines. This removes a lot of optimization possibilities, which is why we'd generally rather not call variables "volatile". For a buffer overflow test, we know that the buffer can't be changed by the program if it's working as intended, so the effect is that we zero the memory, process, and after all I/O is done we check the buffer. That's precisely what we want here.

      If we make the actual buffer "volatile", we really don't gain anything. We know it's going to change, and we won't learn much from examining it later.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    7. Re:Complete nonsense.... by vux984 · · Score: 1

      I'm not sure you typed that in right, or maybe you don't understand what volatile means or when to use it.

      No I typed it in right. That's the point. To guard against security flaws, you need to specify volatile in situations where you explicitly expect it not to be volatile; so that any sanity checks you put in place don't get optimized out as redundant/dead code.

      For security you effectively have to assume all memory is volatile, and that it might be changed when it shouldn't be.

      For a contrived example,

      static buffer
      static int x

      [...]

      somefunction()
      {
        x = 7
        loop
              int y = x;
              do somestuff(buffer) // this doesn't adjust y or x
              sanity check: if y != x call error("WTF somethings horribly wrong! abort!")
        end loop ....
      }

      Neither y nor myvariable are volatile, they aren't supposed to be modified except as assigned above. So why should I mark anything volatile?

      Because during somestuff() the 'buffer' got overrun and it wasn't detected, so x got overwritten during the loop. I had a sanity check, but the compiler optimized it out because it thought nothing updated x or y.

      So now I have to mark x volatile to restore the security check? To tell the compiler, that even though nothing should have altered x or y, I need it to run the sanity check to make sure of that.

      (Yes, yes, the real problem is in somestuff() where the buffer got overrun in the first place, but that's someone else's code or whatever.)

      I have to mark x volatile when its NOT supposed to change externally. Its only 'volatile' because of a 'bug'. Its not volatile by design. If I don't mark it volatile then the sanity check gets optimized away, and the software is vulnerable.

      The trouble is the circumstances of x are the same as ANY other memory in my system, so now it all has to be marked volatile, to ensure my sanity checks evaluate. That's not good.

    8. Re:Complete nonsense.... by vux984 · · Score: 1

      Except that "volatile" means that the memory might be accessed through methods other than the program,

      Exactly right.

      The trouble is in the case of a bug or vulnerability, even non-volatile memory might be accessed/updated when its not supposed to be. And any sanity checks or range changes or bounds checks you might write to try and close the potential holes require the non-volatile memory be marked volatile to prevent the compiler optimizing out the checks.

      See my other reply for a contrived example of what I'm trying to explain.

    9. Re:Complete nonsense.... by Anonymous Coward · · Score: 0

      Any code removal by the compiler can be avoided by avoiding the C insanity. The insanity brought to you by a business partner of NSA and a branch of U.S.G.

      Now, let the propaganda against the Swiss language PASCAL roll in. Please also "explain" why Algol was too perfect to be used. Except in those Unisys mainframes, of course. Explain that too.

    10. Re:Complete nonsense.... by Anonymous Coward · · Score: 0

      (#47284427) reply ::

      The way I learned about volatile is that it is to be used for memory that is modified out of the scope in which it is used.

      If you have that understanding of volatile, then it fits perfectly with its use to prevent a memset() from being removed.
      So, I would / and do use volatile to tell the compiler that I know the "true" scope of the memory it references and that
      it should do each step in the order and frequency that I tell it to the memory in question. So, this sequence is important
      for a theoretical hardware register --

      #include
      int const *volatile a_register = (int const *volatile) 0xffff0002;

      int main(int argc, char *argv[])
      {
            int dummy_read = *a_register;
                    dummy_read = *a_register; // Must read twice to reset the state

            return (0);
      }

      Ask any hardware guy - this is how you program hardware.

      Note that volatile has the same syntacticalconstruction as the const keyword, i.e. right to left association.

    11. Re:Complete nonsense.... by vux984 · · Score: 1

      The way I learned about volatile is that it is to be used for memory that is modified out of the scope in which it is used.

      What about memory that isn't supposed to be modified out of the scope in which it is used? That's the point. bugs/vulnerabilities that lead to memory that is NOT SUPPOSED to be volatile.

      But as soon as you open the can of worms and say, "well... if there's a bug, then maybe it will be modified out of scope somehow... " and then ALL memory is considered volatile.

      If you have that understanding of volatile, then it fits perfectly with its use to prevent a memset() from being removed.

      Why does it fit? The memory you are updating with memset is non volatile. Like any other 'normal' variable or buffer it is not supposed to be read or modified out of scope.

      You have flipped the definition upside down. And as soon as you do that you have to consider the possibility that any other memory in your system that isn't supposed to be modified or read out of scope might, in actuality, be equally 'volatile'.

    12. Re:Complete nonsense.... by ultranova · · Score: 1

      Most security related vulnerabilities arising from compiler optimization tend to revolve around the idea that you are defending against memory being modified externally that should not normally be modified or read from externally.

      In other words, these vulnerabilities don't rise from compiler optimizations but from programmer errors. They only relate to compiler optimizations insofar that those optimizations interfere with ad-hock attempts to get managed language behaviour in an unmanaged language. Which is a bad idea in the first place; either write code that can be checked to be secure by static analysis tools, or switch to a real managed language.

      --

      Forget magic. Any technology distinguishable from divine power is insufficiently advanced.

    13. Re:Complete nonsense.... by ultranova · · Score: 2

      If I don't mark it volatile then the sanity check gets optimized away, and the software is vulnerable.

      Except it's just as vulnerable either way. Your sanity check never executes even if x and y are volatile, since the buffer overrun in somestuff() already transferred control to pwned() when somestuff() tried to return. All your sanity check does is give you a false sense of security.

      Yes, yes, the real problem is in somestuff() where the buffer got overrun in the first place, but that's someone else's code or whatever.

      Yes, and that problem is not solvable in C, no matter how many sanity checks you litter your code with. As soon as you execute any code from an untrusted source, you don't have any security. Any error puts the system into an undefined state, at which point all bets are off.

      --

      Forget magic. Any technology distinguishable from divine power is insufficiently advanced.

    14. Re:Complete nonsense.... by Anonymous Coward · · Score: 0

      Like any other 'normal' variable or buffer it is not supposed to be read or modified out of scope.

      This happens to stack variables all of the time, so yes, memory is a finite resource and
      the same memory is recycled and reused all of the time
      during the life of a process.
      So I'm at a loss as to why you're so rigid in your thinking. We're the programmers;
      we tell the computer our requirements and how to execute them - it's not the other way around.

      Not a personal dig at all, been coding since assembler and have yet to not be able to do
      something in C or assembler (higher level languages impose many artificial constraints
      and really are the bane of our current software security problems, e.g. MicroSoft, et. al.
      IMHO). There are no laws in programming, only rules and guidelines that require flexible,
      testable thinking.

    15. Re:Complete nonsense.... by Darinbob · · Score: 1

      Except that the compiler was buggy in the first place by removing such code. Thus it is "over eager". The article is not really about logically correct dead code removal causes security bugs, but about compilers that incorrectly remove code rather than issuing warning or errors in the case of undefined behavior.

    16. Re:Complete nonsense.... by Darinbob · · Score: 1

      Knowing that the code is being removed by the compiler also means that you know that your compiler is broken. The compiler should have issued a warning pointing out that the code is using undefined behavior, not take that undefined behavior as a lame excuse to try some more optimizations. Of course the C/C++ standards do not dictate that warnings must be issued in these cases.

      The article itself from what I saw, said nothing about security related vulnerabilities, and nothing about buffer overflow checking. But it is about a tool (yet another static analysis tool) that can detect more of these undefined behaviors that could cause some compilers to optimize away the code.

    17. Re:Complete nonsense.... by dkf · · Score: 1

      Most made entire classes of C blunders impossible

      Don't worry about that! They had their own classes of blunders instead. (Every programming language has a characteristic set of problems that come up, and a set of recommended programming practices that avoid those blunders.)

      --
      "Little does he know, but there is no 'I' in 'Idiot'!"
    18. Re:Complete nonsense.... by david_thornley · · Score: 1

      Yup. I was thinking of sections of memory allocated strictly to stay zeroed out and then scanned, presumably part of a larger allocation and put there by placement new. Range and bounds checks will not be optimized out. If you have code that says "make sure i is a valid subscript, and if it is return the array value, otherwise do something else", that's completely conforming and will be compiled normally. (Code that says "Return the array value, oh, and by the way, check i" is subject to having the check removed, since the only way it would fail is already undefined behavior.) Sanity checks can be dropped by the optimizer only if the compiler can prove they're unnecessary, which isn't ideal, but usually isn't that bad.

      With memory you should be using, there's not usually an obvious way to tell whether it's been stomped on or not. If you can tell, you can scan it and do something like raise an exception or output a warning. (That doesn't work for zeroed guard memory, since the compiler can realize that the memory hasn't changed in a conforming way and return the proper scan result. It doesn't work for zeroing out used buffers for much the same reason; I don't have a better solution here than "volatile".)

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    19. Re:Complete nonsense.... by vux984 · · Score: 1

      since the buffer overrun in somestuff() already transferred control to pwned() when somestuff() tried to return

      That is only -one- failure mode, not all buffer overruns will let you overwrite to the instruction pointer to transfer control to your code.

      Security is layered.

      Yes, and that problem is not solvable in C, no matter how many sanity checks you litter your code with. As soon as you execute any code from an untrusted source, you don't have any security. Any error puts the system into an undefined state, at which point all bets are off.

      Gotcha. So unless you write the operating system from the ground up yourself there's always going to be flaws. Thank you captain obvious. But that doesn't mean that sanity checks are worthless - they catch or mitigate flaws all the time.

    20. Re:Complete nonsense.... by vux984 · · Score: 1

      either write code that can be checked to be secure by static analysis tools

      Which just catches a limited subset of vulnerabilities.

      or switch to a real managed language.

      Because you can't write exploitable code in a managed language?

    21. Re:Complete nonsense.... by vux984 · · Score: 1

      The compiler should have issued a warning pointing out that the code is using undefined behavior

      Not all code the compiler removes is using undefined behaviour. I am not talking about undefined behaviors being 'optimized' away.

      The article itself

      Yeah, we've sort of gone off track vis a vis the original article. The scope of issues the original article talks about is smaller, and I agree with you fully that the compilers should be issuing warnings for the particular scenarios they are talking about.

    22. Re:Complete nonsense.... by ultranova · · Score: 1

      Which just catches a limited subset of vulnerabilities.

      Indeed. Everything catches only a limited subset of vulnerabilities in C. C isn't a good language for writing secure software. It's bad even for an umanaged language, since arrays don't store their size, so you need to go out of your way to prevent overflows. That's kinda my point.

      Because you can't write exploitable code in a managed language?

      You can write buggy code in anything, but by definition you can't write code that modifies memory it shouldn't have access to or otherwise puts the runtime in an undefined state in a managed language. That's what "managed" means.

      --

      Forget magic. Any technology distinguishable from divine power is insufficiently advanced.

  5. Bad summary is bad by werepants · · Score: 4, Informative

    This is not really about the existence of bad compiler optimization - it is about a tool called Stack that can be used to detect this, which is known as "unstable" code, and has been used to find lots of vulnerabilities already.

    1. Re:Bad summary is bad by bAdministrator · · Score: 1

      There was a talk covering these issues posted at the ACM in February:
      https://www.youtube.com/watch?...

    2. Re:Bad summary is bad by 14erCleaner · · Score: 1

      Actually it's about non-standard-conforming "security" hacks causing unexpected results. If the result of an operation is undefined, the compiler can insert code to summon Cthulhu if it wants to.

      --
      Have you read my blog lately?
    3. Re:Bad summary is bad by Darinbob · · Score: 1

      But it calls into questions those compilers. Why did the compilers decide to exploit the unstable code to do more optimization rather than pointing out the unstable code as a warning or error? After all the only way that they could do this extra optimization is if they knew that there were some undefined operations that allowed it to make some further analysis, and such undefined operations might be better treated as defective code.

      Although to be fair the examples I saw may have just been oversimplified cases where the journalist was incorreclty explaining what STACK was doing.

      Basically when there are bugs like this, where the compiler optimization changes the behavior of the code, then either the compiler is incorrect or else the compiler was not given all the necessary information (variable was not declared volatile, compiler does not know about side effects or requirements on a particular machine, etc).

    4. Re:Bad summary is bad by dkf · · Score: 1

      Actually it's about non-standard-conforming "security" hacks causing unexpected results. If the result of an operation is undefined, the compiler can insert code to summon Cthulhu if it wants to.

      If your compiler is doing that, you should choose a different compiler. Summoning elder gods just because signed arithmetic might wrap around is not a good cost/benefit tradeoff!

      --
      "Little does he know, but there is no 'I' in 'Idiot'!"
    5. Re:Bad summary is bad by careysub · · Score: 1

      ....Summoning elder gods just because signed arithmetic might wrap around is not a good cost/benefit tradeoff!

      Make that Elder Gods. Respect is essential - we do not wish to arouse their wrath. Nyarlathotep be praised!

      --
      Starships were meant to fly, Hands up and touch the sky - Nicky Minaj
  6. Old news by Anonymous Coward · · Score: 4, Informative

    I know that at least GCC will get rid of overflow checks if they rely on checking the value after overflow (without any warning), because C defines that overflow on signed integers is undefined. This is even documented. If anything is declared by the language specification as being undefined, expect trouble.

    1. Re:Old news by Anonymous Coward · · Score: 0

      The proper way to check is to calculate if an overflow will happen instead of checking to see if an overflow did happen. Stupid lazy programmers, shortcuts, and deadlines.

    2. Re:Old news by Darinbob · · Score: 1

      So why doesn't GCC issue a warning about undefined operations in this case? It certainly issues plenty of warnings in cases that are well defined and not violating any rules.

      What "undefined" means here for most compilers is that it will make the best attempt it can under the C rules but the results may vary on different machines. Ie, it will use the underlying machine code for adding two registers, which may wrap around or possibly saturate instead, and the machine may not even be using tw's complement. However "undefined" should not mean that the compiler can do whatever the hell it wants to do, such as using the undefined operation as an opportunity to perform additional unwarranted optimizations.

      (With GCC it's hard to tell. They had the version in the past that whenever it saw #pragma, whose behavior is undefined, it started up a game of hack. But this was mostly as an easter egg and snarky protest against a vague C standard.)

    3. Re:Old news by Thiez · · Score: 1

      What "undefined" means here for most compilers is that it will make the best attempt it can under the C rules but the results may vary on different machines. Ie, it will use the underlying machine code for adding two registers, which may wrap around or possibly saturate instead, and the machine may not even be using tw's complement.

      No, that would be implementation defined behavior.

    4. Re:Old news by Anonymous Coward · · Score: 0

      > So why doesn't GCC issue a warning about undefined operations in this case?

      Because it would be generating warnings about every other line of your code. Every time you add, subtract or multiply signed integers, you're introducing the possibility of undefined behaviour (if the result overflows, the behaviour is undefined). The compiler can't determine whether UB will occur in practice, because it depends upon the actual values used at run time.

      > What "undefined" means here for most compilers

      It means that they can (and do) assume that cases which invoke undefined behaviour will not happen. They generate code which is correct for the defined cases. For any undefined cases, the result may as well be random.

      The standard is quite explicit about this. As is any decent tutorial. Any competent C programmer knows full well that "X invokes undefined behaviour" is standardese for "don't do X, OR ELSE".

  7. Misleading summary, slashdot by Anonymous Coward · · Score: 2, Insightful

    The kinds of checks that compilers eliminate are ones which are incorrectly implemented (depend on undefined behavior) or happen too late (after the undefined behavior already was triggered). The actual article is reasonable— it's about a tool to help detect errors in programs that suffer here. The compilers are not problematic.

    1. Re:Misleading summary, slashdot by bAdministrator · · Score: 1

      That's true, but also missing the point.
      The main issue is that these situations are not always that obvious in real world code.

    2. Re:Misleading summary, slashdot by Darinbob · · Score: 1

      Why aren't the compilers problematic? From what I have read the compilers seem to be exploiting the undefined behavior as an opportunity to perform additional optimization, whereas the compiler seems like it should instead warn the user about the undefined behavior.

      Maybe it's that the examples that I saw, referenced from the article, are all ones where most basic static analysis tools will flag such code as defective. I haven't seen an example yet where the code is reasonable and does not deserve any compiler warning where a compiler could optimize away valid code.

  8. Simple. by MartinG · · Score: 0

    Use a language that does bounds checking automatically. Its not the 1970s any more.

    --
    -- MartinG To mail me: echo kewyjlcxyzvjfxbqwh | tr bcefhjklqvwxyz .@adgimnoprstu
    1. Re:Simple. by Anonymous Coward · · Score: 0

      Which one those will run on the billions of embedded devices with limited memory and processing power? Oh right, none of them.

    2. Re:Simple. by Desler · · Score: 1

      Unfortunately for those languages, the entire world does not run x86 or other workstation-class or better CPU. Which one of those will run on, for example, the hundreds of millions of 16-bit microcontrollers in wide use? Or MIPS chips in memory-constrained devices like consumer routers? For those requirements, the only usable portable language is C.

    3. Re:Simple. by Anonymous Coward · · Score: 0

      C and C++ became popular because of UNIX and Linux, not necessarily because they were technically good solutions. At the time (1970s), C was recognized as a step backward by those in the know about modelling computing systems.

    4. Re:Simple. by Anonymous Coward · · Score: 1

      We're so impressed with your insights that we want to hire you to get a managed language like Java or .net to run on our CPU (4KB flash and 2KB ram). It will be so nice to not worry about 1970s problems any more.

    5. Re:Simple. by Anonymous Coward · · Score: 0

      Shhh you may scare him off and he wouldnt realize what JIT means. (Meaning just in time compilation....) So those 'safe' languages can do the exact same problem with the code they compile. Even worse you wouldnt know because the emitted code is even more ephemeral...

      Its not the 1970s any more.
      Apparently they dont teach how to think anymore and just regurgitate some meme that sounded sort of good...

    6. Re:Simple. by Desler · · Score: 3, Insightful

      C became popular because it was vastly more portable and performant than its predecessors. It still is today. None of those "better" languages that came before it or after it can beat that. And yes, extreme portability does matter when you have 100s of millions if not billions of devices that can't run anything but assembly or C. It's why the people saying that OpenSSL should be written in Java or C# are morons. Care to tell me how that's going to run on a, for example, Linksys WRT54G with only 8 or 16 MB of RAM, 2 to 4 MB of Flash storage and a 125 to 240 mhz MIPS CPU? Yeah, it's not.

    7. Re:Simple. by Desler · · Score: 1

      But the entire world runs x86 with gigs of RAM and terabytes of storage!! How dare you being reality into this!

    8. Re:Simple. by Desler · · Score: 2

      The problem is that most programmers have never had to get their hands dirty doing embedded work. They live in a bubble that ignores all the memory/storage/processing-power constrained devices all around them. OpenSSL, for example, as used in something like DD-WRT would be unusable if it was written in anything but C or possibly C++.

    9. Re:Simple. by Anonymous Coward · · Score: 0

      C and C++ became popular because of UNIX and Linux, not necessarily because they were technically good solutions. At the time (1970s), C was recognized as a step backward by those in the know about modelling computing systems.

      Pity they were too busy modeling computer systems and real computer science instead of actually implementing those models.

    10. Re:Simple. by Desler · · Score: 3, Insightful

      Well I'd be pretty pissed as well if my pet language was relegated to the graveyard of obscurity by a language that was usable for real work. Dennis Ritchie was a pragmatist who got shit done not some guy wanking over the greatness and purity of the language he created. People to this day are still jealous of that.

    11. Re: Simple. by MartinG · · Score: 1

      Indeed. But that's a different class of problem. Or are compilers optimising constant time comparison routines to not run in constant time these days?

      --
      -- MartinG To mail me: echo kewyjlcxyzvjfxbqwh | tr bcefhjklqvwxyz .@adgimnoprstu
    12. Re:Simple. by Anonymous Coward · · Score: 0

      JIT means "I don't give a shit what the code really does, just that it compiles"

    13. Re:Simple. by K.+S.+Kyosuke · · Score: 1

      C became popular because it was vastly more portable and performant than its predecessors.

      With the exception of Forth. :-)

      And yes, extreme portability does matter when you have 100s of millions if not billions of devices that can't run anything but assembly or C.

      Or Oberon. Oops, there. I said it.

      Care to tell me how that's going to run on a, for example, Linksys WRT54G with only 8 or 16 MB of RAM, 2 to 4 MB of Flash storage and a 125 to 240 mhz MIPS CPU? Yeah, it's not.

      Correct me if I'm wrong, but aren't Tektronix oscilloscopes still running embedded Smalltalk these days?

      --
      Ezekiel 23:20
    14. Re:Simple. by K.+S.+Kyosuke · · Score: 1

      It ran on the Alto. But you really should be using Forth on that CPU, though. It was born for that. (Unless it's one of the dreaded 8051s, of course.)

      --
      Ezekiel 23:20
    15. Re:Simple. by gnupun · · Score: 1

      Use a language that does bounds checking automatically. Its not the 1970s any more.

      Suppose your program accesses millions of array elements in performance sensitive areas. Bounds checking would slow down your code by a factor of 2 or more and therefore should be optional (but not non-existent, like in C).

    16. Re:Simple. by Desler · · Score: 1

      The Alto had at minimum 128 KB so it's not even remotely analogous. Even the most constrained Java ME profile requires 8KB just for itself.

    17. Re:Simple. by Desler · · Score: 1

      I was speaking of RAM of course.

    18. Re:Simple. by K.+S.+Kyosuke · · Score: 1

      And regarding your CPU, I was speaking of Forth, of course.

      --
      Ezekiel 23:20
    19. Re:Simple. by Desler · · Score: 1

      With the exception of Forth. :-)

      Not a systems language so far less usable than C.

      Or Oberon. Oops, there. I said

      Same problem as above.

      Correct me if I'm wrong, but aren't Tektronix oscilloscopes still running embedded Smalltalk these days?

      They might but still has the same limitations as the above and is even more niche.

      I should amend my previous statement to say does not have the same portability and capabilities as C. I would dispute that they're as portable as C (I would love to be proven wrong on this), but even if I did except that they are far less capable than C.

    20. Re:Simple. by david_thornley · · Score: 1

      Sure. Use C++, use std::string and std::vector instead of C-type strings or arrays, and wherever you have brackets you substitute ".at()". Bounds checking guaranteed, and you can globally search for "[" to see if anybody's violating the rules.

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    21. Re:Simple. by K.+S.+Kyosuke · · Score: 1

      Even if you don't like Forth (which is arguably vastly superior in the tiniest applications), why should Oberon be "far less useable" than C? A technical argument, please.

      --
      Ezekiel 23:20
    22. Re:Simple. by Anonymous Coward · · Score: 0

      There are many fallacies your post builds on, all stemming from the original premise that UNIX was built using C, which already laid down the groundwork for its popularization, leading to C++.

      Java and C# are in the same venue as C and C++.

      Once you have a system that can more abstractly model the hardware, you can focus on the algorithms, and have the optimizer given the freedom it needs to re-arrange the code in non-obvious ways, tailored to the execution pipeline of the target hardware environment, interleaving instructions in more optimal ways, inlining where it makes sense, unrolling where it makes sense for caching. See, if we had explored those venues instead of coping with quick fixes like C and C++, optimizations and parallel execution would be taken for granted these days, and yield far better results than what you can possibly hope to get with C and C++. As your post proves, most are stuck in the 1:1 relation with how their source code is typed in and translated to machine code. That's simply not how a more abstract model of the hardware would do it.

      C and C++ are still very close to how assembly language is translated to machine code. It's 99% a 1:1 relationship in how the code is organized in source to how it is organized in code.

      Obviously you are not going to invest time in researching better ways when you have a hammer and some nails to do it right away. Humans do with what gets the job done there and then, and the more who use the same tools, the more you can copy and learn from others, even if it's not the optimal way.

      C could have been far better at what it does, if it had acknowledge it was just another form of of assembly language. As for C++, you have to become a compiler to fully understand the language, or risk writing code you can't predict the behavior of.

      The high societal costs of using C and C++ are staggering, but it will only be known in retrospect.

    23. Re:Simple. by Anonymous Coward · · Score: 0

      Who knows what happened to those investing in the research.

      Now that parallel computing has started to take central stage, you're forced to deal with the abstract modeling problem.

    24. Re:Simple. by Desler · · Score: 1

      Even if you don't like Forth (which is arguably vastly superior in the tiniest applications)

      I don't dislike it. It's still less portable and powerful.

      why should Oberon be "far less useable" than C? A technical argument, please.

      That was my bad. I confused the language. It's usability would be limited by its platform support which is smaller than C.

    25. Re:Simple. by Anonymous Coward · · Score: 0

      languages other than C show other vulnerabilities.

      Look at this example:http://armoredbarista.blogspot.de/2014/04/easter-hack-even-more-critical-bugs-in.html
      They *try* to do crypto in java, but OO in combination with exception-handling gives a timing-side-channel which LEAKS THE KEY.

      Neither OO nor exceptions are in plain C, so using a "better" language gives *additional* vulnerabilities (while it perhaps removes others, *if done right*)

    26. Re:Simple. by Anonymous Coward · · Score: 0

      It's interesting to note that people fear Java taking over their jobs. ;) With neither Java or C# mentioned in the post, but independent posts mention them often, so it must be a sore thumb for some. They have the same flavor as C and C++ and won't qualify as being a solution in any case.

    27. Re:Simple. by Anonymous Coward · · Score: 0

      I want to shove my fetid pregnancy rod into your rancid .at() hole. What say you?

    28. Re:Simple. by Desler · · Score: 1

      There are many fallacies your post builds on, all stemming from the original premise that UNIX was built using C, which already laid down the groundwork for its popularization, leading to C++.

      You ascribe something to me that I never stated. Of course UNIX was not built using C. C was created in order to make Unix portable. The only thing fallacious is your strawman.

      Java and C# are in the same venue as C and C++.

      +5 funny. If they are in the same venue please show me you running Java or C# on an Amtel ATTiny. I won't hold my breath.

      Obviously you are not going to invest time in researching better ways when you have a hammer and some nails to do it right away. Humans do with what gets the job done there and then, and the more who use the same tools, the more you can copy and learn from others, even if it's not the optimal way.

      +5 funny. Half my job is programming in C# so you would be wrong again.

      C and C++ are still very close to how assembly language is translated to machine code. It's 99% a 1:1 relationship in how the code is organized in source to how it is organized in code.

      LOL. That hasn't been true for decades. C and C++ translate horribly to modern vector assembly language instructions. Even the best of vectorizing compilers are laughably bad. If what you said was true Intel and others wouldn't be constantly reinventing extensions to C to allow better vectorizing of the code.

      C could have been far better at what it does, if it had acknowledge it was just another form of of assembly language. As for C++, you have to become a compiler to fully understand the language, or risk writing code you can't predict the behavior of.

      C would be far better if lots of things were changed about it. C is a very flawed language, but it's still the best portable language around.

    29. Re:Simple. by Desler · · Score: 1

      Hubris is always funny. These are the same people who will write Javascript code that has XSS flaws or will write database interfacing code that is subject to SQL injection attacks while at the same time talking about how secure, memory-safe, etc. the language they use is.

    30. Re:Simple. by Desler · · Score: 1

      Yes but knowing about that would require the GP and his ilk to get better talking points. Most of them have never used C or C++ and are merely parroting random crap they hear from other people who have also likely never used them either. C and C++ are anything but perfect, but for a number of domains/platforms they are basically they best you're going to get unless you want to dive into a usually shitty, proprietary vendor language or assembly.

    31. Re:Simple. by Desler · · Score: 1

      Now that parallel computing has started to take central stage, you're forced to deal with the abstract modeling problem.

      Nah, already been solved by things like OpenMP. It's cross-platform, cross-vendor, etc.

    32. Re:Simple. by Anonymous Coward · · Score: 0

      C and C++ translate horribly to modern vector assembly language instructions.

      Most code, in fact the vast majority of code, is not suitable for and do not benefit from vector instructions. Where it is, use a language which is suitable.

    33. Re: Simple. by Anonymous Coward · · Score: 0

      I think he is one of the Nihilist Shills who essentially sides with the government with their Cyber War Efforts."you need a way to control the plebs and their computors".

    34. Re:Simple. by Anonymous Coward · · Score: 0

      So we use a shitpile of C that gives an illusion of security ? Plus, you claim is probably FALSE.

      I write in C++ for a device with 4096 bytes of RAM and about 32kByte of ROM. Works like a charm.

    35. Re:Simple. by Anonymous Coward · · Score: 0

      Folks have a dark agenda. No use to argue with them.

    36. Re:Simple. by Anonymous Coward · · Score: 0

      I am certainly not jealous of the Creator Of The Cyber War Domain.

    37. Re:Simple. by Anonymous Coward · · Score: 0

      I use C++ every day but I don't know how 64bit Integer overflow is supposed to be properly checked. With Ada it is well-defined, though.

      Which again leads to "C is a regression from the days of Algol".

    38. Re:Simple. by jonwil · · Score: 1

      But can you write for that device in a language that has proper bounds checking built in from the get go?

    39. Re:Simple. by lgw · · Score: 2

      More than that, string and vector are just as fast as the vulnerable C alternatives as long as you pre-allocate the buffers to the expected size. It's not rocket science, but the number of times I've heard "but C++ is too slow, we have to use C" makes me cry. With bounds checking in both (hand-written in C, of course), the speed is the same. Without buffer checking in either, the speed is the same.

      --
      Socialism: a lie told by totalitarians and believed by fools.
    40. Re:Simple. by Anonymous Coward · · Score: 0

      Every bounds check will add something like

      CMP
      JMP
      CALL ERRORHANDLER

      if the compiler decides a check must be done. That will be in the order of 3*4 == 12 bytes. Which is bearable even for Arduinos, given the security/safety benefit.

      Plus, it can in many cases be optimized away from the inside of a loop and must be done only once or even never, if constants are propagated.

    41. Re:Simple. by Anonymous Coward · · Score: 0

      I doubt that. Either you'll access elements in a predictable order, in which case the compiler will likely recognize what you are doing and will be able to eliminate bounds checks, or you'll access elements unpredictably, in which case the CPU will fail to prefetch and you will spend most of the time waiting for memory, rendering the bounds checking overhead insignificant.

    42. Re:Simple. by Anonymous Coward · · Score: 0

      My language expression sucks! I was saying C is "best" today only because it was widely adopted, not because it was good, and that's where I think we agreed.

    43. Re:Simple. by Desler · · Score: 1

      No, I think C is a great langauge. It has its flaws but no langauge is perfect and the ones that claim to be are extremely niche or long since dead.

    44. Re:Simple. by Anonymous Coward · · Score: 0

      Sorry, C is still the best portable assembler we have.

    45. Re:Simple. by badkarmadayaccount · · Score: 1

      Ever heard of Ada and Fortran?

      --
      I know tobacco is bad for you, so I smoke weed with crack.
  9. Re:Unstable Code, again by Anonymous Coward · · Score: 0

    Apparently, no one told USENIX about this 22 year old revelation.

    (also, I was compelled to fix the typo in my Re: of your title, unless you really meant "Code unrelated to sables", which I assume would cover most code)

  10. Floating point algorithms too by Anonymous Coward · · Score: 2, Informative

    Compilers can also "optimize" away Kahan summation algorithm. See page 6 of How Futile are Mindless Assessments of Roundoff in Floating-Point Computation

  11. Simple. by Anonymous Coward · · Score: 0

    #fail

    It's not just bounds checking -- if you want to securely compare 100 bytes, you need to compare all 100 bytes. An optimized algorithm (intentionally or via compiler) that exits after the first mismatch leaks information. This isn't some pie in the sky hypothetical attack, it's been used to break passwords since the 70s (if not earlier).

  12. Bad advice by HalfFlat · · Score: 1

    Short of bugs in the compiler's optimizer — and we all know there have been many — the idea that "if the entire code absolutely must stay fully intact, it shouldn't be optimized" is already dangerous.

    A compiler conforming to its documentation or standard isn't going to change semantics that have been guaranteed by that document. Those guarantees though are all you have: even without explicit optimization options, a compiler has a lot of freedom in how it implements those semantics. Relying on a naïve translation from a line of code to a particular, non-guaranteed assembly representation is a very brittle practice.

  13. Functionally correct, but insecure by Smerta · · Score: 5, Insightful

    The classic example of a compiler interfering with intention, opening security holes, is failure to wipe memory.

    On a typical embedded system - if there is such a thing (no virtual memory, no paging, no L3 cache, no "secure memory" or vault or whatnot) - you might declare some local (stack-based) storage for plaintext, keys, etc. Then you do your business in the routine, and you return.

    The problem is that even though the stack frame has been "destroyed" upon return, the contents of the stack frame are still in memory, they're just not easily accessible. But any college freshman studying computer architecture knows how to get to this memory.

    So the routine is modified to wipe the local variables (e.g. array of uint8_t holding a key or whatever...) The problem is that the compiler is smart, and sees that no one reads back from the array after the wiping, so it decides that the observable behavior won't be affected if the wiping operation is elided.

    My making these local variables volatile, the compiler will not optimize away the wiping operations.

    The point is simply that there are plenty of ways code can be completely "correct" from a functional perspective, but nonetheless terribly insecure. And often the same source code, compiled with different optimization options, has different vulnerabilities.

  14. Simple. by Anonymous Coward · · Score: 0

    lol, why not just use haskell or lisp or some other weenie language where you can mathematically prove it correct? Oh, because sitting around pulling your pud doesn't get the job done.

  15. Yeah, Ok, I'll say it if no one else will ... by Anonymous Coward · · Score: 0

    Gentoo funroll-loops dweebs.

  16. Functionally correct, but insecure by Anonymous Coward · · Score: 1

    Yes! Failure to wipe memory is like failure to wipe asshole. You save some time by not doing it but you have smell like shit and people know where you have been.

  17. The more things change.... by sconeu · · Score: 1
    --
    General Relativity: Space-time tells matter where to go; Matter tells space-time what shape to be.
  18. In other news... by Anonymous Coward · · Score: 0

    Undefined behaviors don't behave in a defined manner.

  19. Bad workman blames his tools etc... by Anonymous Coward · · Score: 0

    These moronic programs are scanning off the end of allocated memory to do what? Execute that memory if it contains random data, but not if it is detected as malicious code? Please. If the compiler is compliant to the language standard and it opens up a security hole in your crappy code when optimizing then that is your bug.

  20. What's the would-overflow operator? by tepples · · Score: 1

    So what's the standard-conforming way to determine whether a particular integer operation will not overflow? And are compilers smart enough to optimize the standard-conforming way into something that uses the hardware's built-in overflow detection, such as carry flags?

    1. Re:What's the would-overflow operator? by Anonymous Coward · · Score: 0

      You have to use the next-larger data type to make the test. So to securely add to int32 you need to use an int64.

      WHICH IS OF COURSE INSANE SHIT. How do you test 64 bit additions for overflow ?

      Here's the protip: Avoid the Bell Labs Cancer and use Ada. They have all of this nicely defined in the language specification.

    2. Re:What's the would-overflow operator? by Darinbob · · Score: 1

      Until you actually need to exploit the undefined behavior. It's somewhat common to have a range of numbers that wraps around rather than distinctly having a smallest and largest value. Ie, indices into a circular buffer for example. You may want a 16-bit value that acts as a sequence number on unacknowledged packets. Eventually it wraps around so that sequence number 1 is actually larger than sequence number 65534. Then you can do operations to see if X is greater than Y in such a system. But most languages don't support such number systems, so you cheat a bit (ignore the overflow bit and use a cast here and there). Same applies for 32 and 64 bit numbers.

    3. Re:What's the would-overflow operator? by Euler · · Score: 1

      It's turtles all the way down...

      resort to the long long long type?

    4. Re:What's the would-overflow operator? by david_thornley · · Score: 1

      Use unsigned integers. Their behavior is perfectly defined. (Yes, this is a pain, but it's the standard thing to do.)

      --
      "When you have eliminated the unacceptable, whatever is left, however improbable, must be the truthiness" - Holmes
    5. Re:What's the would-overflow operator? by Anonymous Coward · · Score: 0

      Then you use unsigned types. Overflow is perfectly defined behavior for those.

  21. Complete nonsense.... by khb · · Score: 1

    "...decide it's an error.."

    No, it is an "optimizing" compiler not a "correcting" compiler. The optimizer can detect that no language defined semantic will be changed by removing the code, so it does. As others have noted, "volatile" is the fix for this particular coding / compiler blunder. However ill-defined, it is *not an error*.

    As for the folks commenting that only C can run in small embedded processors that's hogwash. Huge mainframes of the early ages had smaller memory sizes and ran FORTRAN (now Fortran, but then it was all caps), COBOL, PL/I (and .8 for IBM internals), Algol and other languages. Most made entire classes of C blunders impossible, and there is no fundamental reason why we couldn't go back to safer languages for embedded programming (and good reasons why we ought to; not that I expect we shall).

  22. Re:Functionally correct, but insecure by Anonymous Coward · · Score: 0

    Which is why good IDEs and error messages are so important. When integrated with the compiler it can highlight the code, log a warning, and say ''hey, this doesn't seem to effect anything and will be removed" and the programmer will know there's a potential bug.

    Many IDEs have their own checks to do a little of this, but there are lots of room for improvement.

  23. Re:Functionally correct, but insecure by Anonymous Coward · · Score: 0

    The point is simply that there are plenty of ways code can be completely "correct" from a functional perspective, but nonetheless terribly insecure. And often the same source code, compiled with different optimization options, has different vulnerabilities.

    And this is exactly the reason the BSD and Apple folks developed the CLANG Compiler.

    When I started using Gentoo in 2003, I began reading up on optimizations and what could happen only to discover that the compiler could introduce unreproduciable errors in the software along with changing the md5 hash each and every time it compiled things. This didn't make me happen then and it hasn't gotten any better other then with the Clang compiler and Gentoo now offers it as an option for building instead of the GCC toolchain.

  24. Re:Functionally correct, but insecure by lgw · · Score: 1

    Your complier constantly removes tons of unneeded code under optimization. It can't possibly be a warning to do this, or you'd drown in them.

    --
    Socialism: a lie told by totalitarians and believed by fools.
  25. Functionally correct, but insecure by Anonymous Coward · · Score: 0

    My making these local variables volatile, the compiler will not optimize away the wiping operations.

    Not necessarily. When those variables go out of scope whether they are volatile or not is irrelevant. When in scope does "volatile" mean "this variable can change while I'm using it" or "some unknown code reads this variable when I change it". Not clear and if it's the first then the zeroing can still be optimized out.

  26. Re:Functionally correct, but insecure by Darinbob · · Score: 1

    If there is external evidence that the compiler needs in order to compile/optimize correctly then it needs to be given to the compiler. Thus the addition of "volatile". Other compilers have a way to add options on the command line, such as indicating that the machine uses strict alignment.

    The problem here is however not that there is some strange stuff happening with the program, and that code is being optimized away because the compiler can prove that it serves no purpose given the lack of additional information. The problem is that the compiler sees a code performing an operation that has undefined behavior and then "deduces" that it can perform additional optimization based on that (the article did not talk about security holes, this seems to be added in this summary only). However I think such compilers should instead issue a warning about the undefined behavior, or at the very least not try to exploit such behavior and remove the code altogether. It's extremely pedantic to say that because the code has undefined behavior then generating code that does nothing is a valid option, especially without warning the user that you're doing this.

    The examples given in the article did not appear to be fully functionally correct, all of them would have caused a static code analysis tool to complain.

  27. Re:Functionally correct, but insecure by Anonymous Coward · · Score: 0

    if you have tons of unneeded code, you've probably done something very, very wrong. All dead code is begging for a security hole.

  28. Re:Functionally correct, but insecure by DamnStupidElf · · Score: 1

    Unless all the code running on the machine is absolutely type-safe and only allows "safe" reflection then trying to hide sensitive data from other bits of code in your address space is a lost cause. Code modification, emulation, tracing, breakpoint instructions, hardware debugger support, etc. are all viable ways for untrusted code with access to your address space to steal your data.

    Wiping memory is only effective for avoiding hot or cold boot attacks against RAM, despite its frequent use for hacking terrible operating systems to hope/pretend that userspace software isn't leaking data into other processes either directly via attacks or accidentally through kernel mishandling of memory.

  29. My approach to the subject by spaceyhackerlady · · Score: 1

    I always insist on a clean compile with the warning level turned up as high as it will go. If the compiler is cool with my code, I have a better chance it will do the right thing with it.

    Once I have an application that works I see if it meets performance goals (if any). If it does, I'm done. If it doesn't, profile, find the hot spots, optimize as needed. Compiling an entire application with -O3 is idiotic, and misses the point.

    ...laura

    1. Re:My approach to the subject by Anonymous Coward · · Score: 0

      With gcc, some warnings only show up during O3 compiles. Different optimizations analyze the code in different ways, exposing new things to warn about.

    2. Re: My approach to the subject by spaceyhackerlady · · Score: 1

      Example?

  30. Don't rely on undefined behavior by Anonymous Coward · · Score: 0

    Most of these problems originate from the the programmer relying on undefined behavior. If the language definition doesn't state the behavior explicitly (or if it says the behavior is undefined, or implementation specific) - don't use that "feature".
    Excellent writeup by Valve's Bruce Dawson here.

  31. Re:Functionally correct, but insecure by Anonymous Coward · · Score: 0

    If there is external evidence that the compiler needs in order to compile/optimize correctly then it needs to be given to the compiler. Thus the addition of "volatile".

    Not quite true. According to the standard, the compiler is not allowed to optimize sections touching volatile memory *at all*.

  32. Re:Functionally correct, but insecure by Thiez · · Score: 1

    Volatile tells the compiler it may not eliminate or introduce reads and writes to a variable that did not exist in the source code. They also cannot be reordered with respect to other volatile variables.

  33. Partly programmers fault by Anonymous Coward · · Score: 0

    After RFA and RFP, in some cases this does look like the compiler should give better support.

    But a lot of these would be avoided if programmers expressed exactly what they want instead of trying to be "cute" and pre-optimizing their code to be "short". It would also really improve readability

    For God's sake, /. comment system sucks, writing code in it winds up with it cutting out large parts of my comment. So I'll just have to manage without actually code sample from the paper. Instead of using buf + len buf to check for wrap-around for huge len, actually compare len to buf_len and be done with (this is clearer to any idiot too). Similarly, whomever thinks doing (-arg1 0) == (arg1 0) for testing for the special value of INT_MIN (or LONG_MIN or whatever it is in your system) instead of just testing against the damn constant is a moron. It's just inviting trouble.

    I think that if you're doing something that is "clever," just stop. Write it clearly. If it's clever for people, maybe you're being too clever by half and the compiler will guess wrong too.

  34. Re:Functionally correct, but insecure by lgw · · Score: 1

    Flatly false.

    Good code has plenty of null-checking, for example, most of which a clever compiler can prove is unreachable. It's still completely good code.

    Compilers remove code that is provably unreachable on this build. Good defensive coding includes protection against future code changes.

    --
    Socialism: a lie told by totalitarians and believed by fools.
  35. 8 months old news by Anonymous Coward · · Score: 0

    http://developers.slashdot.org/story/13/10/29/2150211/how-your-compiler-can-compromise-application-security