Stories
Slash Boxes
Comments

SoylentNews is people

posted by martyb on Saturday December 02 2017, @01:48PM   Printer-friendly
from the see-what-we-did-there? dept.

https://www.cossacklabs.com/blog/macros-in-crypto-c-code.html

Like death and taxes, one thing that you can be sure of is that using C macros in a modern software project will cause a debate. While for some macros remain a convenient and efficient way of achieving particular programming goals, for others they are opaque, introduce the unnecessary risk of coding errors, and reduce readability.

The criticism of macros is particularly acute in the wider security community. Among Cossack Labs' engineers and the core Themis crypto library contributors there are people who previously worked on auditing cryptographic implementations of critical code. Their typical knee-jerk reaction to macros was always "kill it with fire and never use it again". Taking no sides, we would like to assess both pros and cons of using such dangerous things as macros in security code (as we faced the issue when developing Themis) and suggest some techniques for lowering the accompanying risks.

We'll also discuss a custom "for-audit" build target for Themis designed specifically to generate source code that exposes the macros to inspection because we appreciate the need for security software to be subject to detailed source code scrutiny.


Original Submission

 
This discussion has been archived. No new comments can be posted.
Display Options Threshold/Breakthrough Mark All as Read Mark All as Unread
The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
  • (Score: 4, Interesting) by acid andy on Saturday December 02 2017, @02:50PM (9 children)

    by acid andy (1683) on Saturday December 02 2017, @02:50PM (#604286) Homepage Journal

    I can sort of see the argument that they make security critical or safety critical code harder to properly audit in that they add a layer of obfuscation over the raw code but for much the same reason I strongly disagree with the criticism that they reduce readability. One of the key benefits of a macro is that, if used sensibly, it can reduce an ugly, unwieldy, hard to read expression, to a short, human readable form. For those that are religiously against macros, it would be easy enough to replace one with an inline function in many cases but you'd still have to code hop to the function definition to read it so I don't see that it would help the readability hugely.

    --
    If a cat has kittens, does a rat have rittens, a bat bittens and a mat mittens?
    Starting Score:    1  point
    Moderation   +2  
       Interesting=2, Total=2
    Extra 'Interesting' Modifier   0  
    Karma-Bonus Modifier   +1  

    Total Score:   4  
  • (Score: 3, Interesting) by tonyPick on Saturday December 02 2017, @04:03PM (1 child)

    by tonyPick (1237) on Saturday December 02 2017, @04:03PM (#604312) Homepage Journal

    it would be easy enough to replace one with an inline function in many cases but you'd still have to code hop to the function definition to read it so I don't see that it would help the readability hugely.

    Playing devils advocate (even though I agree with your general point), one issue is that functions are easier to reason about than macros in C, since function calls will always be pass by value, but macro implementations can change argument values in place in unexpected ways, or create shadow variables which lead to unexpected/incorrect results.

    Quick example would be mixing postfix operators with macros: something like" #define SQUARE(x) ((x)*(x))" Can be passed "SQUARE(x++)" which expands as "(x++) * (x++)" - x gets incremented twice, rather than once, and the result will probably not be what you expect. You can't make this mistake with a function call.

    • (Score: 4, Informative) by Pino P on Saturday December 02 2017, @11:57PM

      by Pino P (4721) on Saturday December 02 2017, @11:57PM (#604469) Journal

      Can be passed "SQUARE(x++)" which expands as "(x++) * (x++)" - x gets incremented twice, rather than once

      No, that's undefined behavior because the two uses of ++ are unsequenced [wikipedia.org]. A high-quality compiler ought to emit a diagnostic for easily detectable undefined behaviors such as this.

  • (Score: 2) by theluggage on Saturday December 02 2017, @04:10PM

    by theluggage (1797) on Saturday December 02 2017, @04:10PM (#604314)

    For those that are religiously against macros, it would be easy enough to replace one with an inline function in many cases but you'd still have to code hop to the function definition to read it so I don't see that it would help the readability hugely.

    Well, that's no harder than looking up what a macro does, and by using a function you can define the types of the arguments and the return value so they get checked, and it avoids sneaky side effects that you can get by using "++" or "&" in a macro so suddenly it can change your parameters. Back in the good old days, using a macro rather than a function call would save you a bunch of clock cycles - in 2017, clock cycles are cheap, and it should be the compiler's job to optimise your code by automatically inlining functions.

  • (Score: 3, Informative) by Thexalon on Saturday December 02 2017, @05:42PM (5 children)

    by Thexalon (636) on Saturday December 02 2017, @05:42PM (#604327)

    Some of the advantages of inline functions over macros:
    1. There are a lot fewer pitfalls with functions than macros. For instance, if I have:
    #define sub(A, B) A-B

    that's easy to mess up with sub(6+5, 6+3), which returns not 2 (like you might expect) but 8. And you can get around that with parentheses and such, but it's an easy mistake to make. By contrast, if you define the exact same concept as an inline function, it's clear. simple, and correct:
    inline function sub(a, b) { return a-b; }

    2. It's a lot easier to fully test an inline function than a macro, in part because of pitfalls like I just described.

    The one place where macros make sense is for the preprocessor adjusting for different C compilers and environments and such.

    --
    The only thing that stops a bad guy with a compiler is a good guy with a compiler.
    • (Score: 3, Informative) by bart9h on Saturday December 02 2017, @06:14PM (4 children)

      by bart9h (767) on Saturday December 02 2017, @06:14PM (#604338)

      #define sub(A, B) A-B

      Giving a obviously, and specially bad, use of something as an argument against it?
      Everyone knows that should be written as

      #define SUB(a,b) ((a)-(b))

      which has none of the problems you mentioned.

      • (Score: 3, Informative) by Thexalon on Saturday December 02 2017, @06:37PM (2 children)

        by Thexalon (636) on Saturday December 02 2017, @06:37PM (#604345)

        You skipped right over this sentence:

        And you can get around that with parentheses and such, but it's an easy mistake to make.

        Good language constructs are those that make it difficult to get wrong and make it easy to catch when you get it wrong. This is like pointing the gun at your own foot - not necessarily wrong, but you're asking for trouble.

        In my example failure, even if you had a little test function, odds are very likely that you did something like this:
        assert(15 == sub(23, 8));
        And you ran the test suite, saw that the assertion passed, and were happy with it because your test covered the code nicely and was correct. And that means that when the bug crept in, this wouldn't be high on your list of things to look at. Especially because a likely result of the error is continuing the program with the wrong value and having a problem in a completely different area of the code because of that incorrect value, rather than a crash right away that you can figure out via a stack trace (and even if you can get a stack trace, the trace points you to where the macro is referenced, rather than the macro itself, so you have to go digging through the header files to find it). Or, even worse, and entirely possible, the incorrect value gets given back to the users as output, and because they either can't or don't double-check with their own calculations, it can even look like the program works correctly even though it's wrong.

        Yes, I used an intentionally trivial example. In a more complex expression, it's more likely this mistake will occur and not get caught until it's a lot harder to sort out.

        --
        The only thing that stops a bad guy with a compiler is a good guy with a compiler.
        • (Score: 3, Insightful) by fyngyrz on Saturday December 02 2017, @11:07PM (1 child)

          by fyngyrz (6567) on Saturday December 02 2017, @11:07PM (#604449) Journal

          it's an easy mistake to make.

          Not if you're actually competent with c, it isn't.

          The argument you're making is essentially "cripple the language (or the use of it) to safety-net incompetent practitioners."

          My argument is: Indulge in some self-improvement. If you don't have a good grasp of how to properly write a c macro, then either don't write them, or go improve your competence with them (seriously, WTF are you, or your employees, doing writing production c code if you don't understand the preprocessor???). For organizations / businesses, pick people with better skillsets (and stop triaging employment by irrelevant crap... it's skill you actually need, so start looking at that, and only that.)

          TL;DR: It's not the c macro system. It's incompetent practitioners.

          • (Score: 2) by coolgopher on Sunday December 03 2017, @12:32AM

            by coolgopher (1157) on Sunday December 03 2017, @12:32AM (#604483)

            While I agree with you in broad strokes, the C macros are very clunky and don't fit into the language particularly well for anything remotely advanced. Then again, in many ways it's its lack of knowledge of C that makes it powerful - you can run rough-shod over all manner of things (not that you should, in 99% of cases, of course).

      • (Score: 2) by crafoo on Saturday December 02 2017, @11:53PM

        by crafoo (6639) on Saturday December 02 2017, @11:53PM (#604466)

        No, that's part of the main point against macros: not everyone knows "#define sub(A, B) A-B" is a bad macro. Most people can write an inline function that subtracts values.

        Also the argument that macros make code more readable is patently ridiculous. It makes it more readable to someone who ASSUMES they know what a macro is doing.

        Anyway, whatever. Programmer arrogance keeps many people employed. They get a kick out of fuzzing your shit macros.