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."

145 of 199 comments (clear)

  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 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.

    10. 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.

    11. 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.

    12. 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
    13. 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.

    14. 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)

    15. 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.
    16. 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
    17. 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.
    18. 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?
    19. 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.

    20. 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.

    21. 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.
    22. 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.

    23. 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.

    24. 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.

    25. 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.
    26. 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
    27. 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.

    28. 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.

    29. 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.
    30. 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?
    31. 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
    32. 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.

    33. 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
    34. 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
    35. 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.

    36. 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.
    37. 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) {

    38. 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.

    39. 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?
    40. 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.
    41. 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.

    42. 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"

    43. 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/...

    44. 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
    45. 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

    46. 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.

    47. 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.

    48. 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.

    49. 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.

    50. 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.

    51. 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.

    52. 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).

    53. 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.

    54. 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.

    55. 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
  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 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'.

    10. 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.

    11. 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.

    12. 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.

    13. 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.

    14. 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'!"
    15. 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
    16. 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.

    17. 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?

    18. 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.

    19. 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 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.)

    2. 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.

  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. 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

  9. 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.

  10. 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.

  11. 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.

  12. 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.

  13. 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.

  14. 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.

  15. 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!

  16. 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++.

  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. 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.

  19. 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
  20. 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
  21. 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
  22. 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).

  23. 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.

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

    I was speaking of RAM of course.

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

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

    --
    Ezekiel 23:20
  26. 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 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.

    2. 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?

    3. 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
  27. 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.

  28. 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
  29. 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
  30. 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.

  31. 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.

  32. 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.

  33. 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.

  34. 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.

  35. 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).

  36. 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?

  37. 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.
  38. 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.
  39. 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.

  40. 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.

  41. 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 spaceyhackerlady · · Score: 1

      Example?

  42. 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.

  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: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.
  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.