[HN Gopher] A primer on some C obfuscation tricks
       ___________________________________________________________________
        
       A primer on some C obfuscation tricks
        
       Author : simonpure
       Score  : 54 points
       Date   : 2020-04-23 20:39 UTC (2 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | TimSchumann wrote:
       | Thanks for sharing this!
        
       | jackhalford wrote:
       | > x[index] is *(x+index) > index[x] is legal C and equivalent too
       | 
       | Can't be unseen, I can't believe I never thought of that.
        
         | guitmz wrote:
         | I find that after learning assembly language, things like this
         | become very obvious when seen in different languages, specially
         | C
        
           | roywiggins wrote:
           | The main reason that works is historic, I think.
           | 
           | It could just as easily throw a compilation error to index a
           | constant with an array rather than the other way around. I
           | don't think this works in Rust even if the resulting machine
           | code for array indexing is the same.
        
             | eMSF wrote:
             | The main reason is that in C, "indexing" an array is purely
             | syntactic sugar for pointer arithmetic, which itself is
             | commutative; that is. ((A)[B]) is equivalent to ((A)+(B)),
             | which itself is equivalent to ((B)+(A)) (assuming one of
             | them has an integral type and the other a pointer to
             | complete object type).
             | 
             | Now, of course an array type isn't a pointer type, but as
             | "indexing" isn't one of the very few cases where an
             | expression that has an array type isn't converted to an
             | expression with a pointer type, you aren't really indexing
             | an array, but a pointer to its first element.
        
           | saagarjha wrote:
           | I see no reason why this should be obvious; it's just a
           | historical quirk of array indexing in C being a _literal_
           | translation to pointer arithmetic. In C++, for example, there
           | is no way to support this with the subscript operator.
        
       | inetknght wrote:
       | Today I learned... _magic_                   #include <cstdio>
       | void sw(int s)         {             switch (s) while (0) {
       | case 0:                     printf("zero\n"); continue;
       | case 1:                     printf("one\n"); continue;
       | case 2:                     printf("two\n"); continue;
       | }         }
       | 
       | [0] https://gcc.godbolt.org/z/Q26LWG
        
         | lostmsu wrote:
         | Huh, what does it do?
        
           | strbean wrote:
           | Looking at the link, it generates the exact same assembly
           | (and behavior of course) as                   void sw(int s)
           | noexcept         {             switch (s) {
           | case 0:                     printf("zero\n"); break;
           | case 1:                     printf("one\n"); break;
           | case 2:                     printf("two\n"); break;
           | }         }
        
             | saagarjha wrote:
             | thatsthejoke.jpg
        
               | strbean wrote:
               | I mean, parent seemed an awful lot like someone asking
               | what it did. Damn me for missing the invisible /s. I'm
               | sure no other reader would ever be curious!
        
               | saagarjha wrote:
               | It's not the comment that is the joke, but the example in
               | the context of the "C obfuscation tricks" article where
               | it's just a convoluted way to write the same thing as a
               | simple C construct.
        
         | MauranKilom wrote:
         | Hey wait, that's just Duff's... Oh.
        
       | saagarjha wrote:
       | Is it bad that I've written some of these in my normal code? In
       | particular, I use the concepts in these when they're relevant:
       | *(c ? &x : &y) = v;            return (char *[]){"No",
       | "Yes"}[!!x];
       | 
       | (Note: for the second one, I use the "selecting from a temporary
       | array" and !! separately; if I only had two options then I'd use
       | x ? "Yes" : "No" of course.)
        
         | bear8642 wrote:
         | >return (char *[]){"No", "Yes"}[!!x];
         | 
         | Is !!x equivalent to x here?
        
           | saagarjha wrote:
           | No, it "collapses" an integer to 0 or 1. (Essentially, it's x
           | != 0.)
        
         | jackewiehose wrote:
         | > Is it bad that I've written some of these in my normal code?
         | 
         | yes
        
       | moonchild wrote:
       | ({_:&&_;});            ({});            ({;});
       | 
       | All of these rely on a gcc extension ('statement expressions').
       | 
       | ________________________________                 a = '-'-'-'
       | 
       | You can also do:                 a = '/'/'/'
       | 
       | To generate a 1 instead of a 0.
       | 
       | ________________________________                 printf("%d
       | %d\n", 0 == sizeof(count = 2, count++), count);
       | 
       | This works because:
       | 
       | 1. There are two forms of sizeof; sizeof(T) where T is a type,
       | and sizeof x where x is an expression.
       | 
       | 2. There are 'comma expressions'; if you have (x, y) where x and
       | y are expressions, then x is executed and the expression
       | evaluates to y.
       | 
       | 3. Parameters to sizeof are not evaluated (which is important
       | because otherwise the value of the 3rd argument would be
       | undefined, since there's no sequence point between evaluation of
       | function parameters).
        
         | saagarjha wrote:
         | > Parameters to sizeof are not evaluated
         | 
         | Oh, but they are ;) Try running sizeof on a VLA sometime.
        
         | sigjuice wrote:
         | $ cat sizeof.c            #include <stdio.h>               int
         | main(int argc, char *argv[])       {           printf("%zu\n",
         | sizeof(int[argc - 2]));       }            $ make -B sizeof
         | cc     sizeof.c   -o sizeof            $ ./sizeof foo       0
         | $ ./sizeof       17179869180
        
       | freefal wrote:
       | What does the provided example do?
       | 
       | 5) Surprising math:
       | 
       | int x = 0xfffe+0x0001;
        
         | [deleted]
        
         | moonchild wrote:
         | It looks a bit like a binary exponent, but according to clang
         | and gcc it's erroneous: 'invalid suffix '+0x0001' on integer
         | constant'.
        
         | monocasa wrote:
         | It doesn't compile.
         | 
         | It's trying to parse the e as scientific notation I think.
         | surprising_math.c: In function 'main':
         | surprising_math.c:4:10: error: invalid suffix "+0x0001" on
         | integer constant         int x = 0xfffe+0x0001;
         | ^~~~~~~~~~~~~
        
           | inetknght wrote:
           | Indeed, I think you're exactly right. Changing it to
           | `0xffff+0x0001` lets it compile.
        
         | inetknght wrote:
         | It produces an error message.
         | 
         |  _error: invalid suffix '+0x0001' on integer constant_
         | 
         | [0] https://gcc.godbolt.org/z/pR5L6v
        
         | rightbyte wrote:
         | That is really stupid. How is that not a bug? I can't belive
         | GCC wont compile it. What does other compilers do.
         | 
         | Edit: Clang also gives an error. Mscv seems to compile. I
         | wonder who follows spec. I assume not mscv ...
        
       | faehnrich wrote:
       | That index[x] was used in one of my favorite IOCCC one-liners.
       | 
       | http://faehnri.ch/have-fun/
        
       ___________________________________________________________________
       (page generated 2020-04-23 23:00 UTC)