[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)