4

The outcome of the following macro is clear:

#define CRASH() do {\
  *(int *)(uintptr_t)0xbbadbeef = 0;\
  ((void(*)())0)();\
} while (false)

My question is, what does the line

((void(*)())0)();

break down to, in English? For example, "this is a function that returns a pointer to a...."

MM.
  • 4,224
  • 5
  • 37
  • 74
  • Note: there is a trailing backslash missing on the 3rd line. – wildplasser Mar 22 '12 at 15:24
  • @wildplasser On the first one too. – R. Martinho Fernandes Mar 22 '12 at 15:26
  • 1
    http://www.youtube.com/watch?v=Q75MZws4ltw#t=1m27s – Karoly Horvath Mar 22 '12 at 15:34
  • 2
    The expression has different meanings in C and in C++. The empty parenthesis in C mean ... function taking unspecified, but fixed, arguments. In C++ they mean ... function taking no arguments (*like `fx(void)` in C*). – pmg Mar 22 '12 at 15:36
  • @pmg I think it will crash and burn no matter... – Lundin Mar 22 '12 at 15:41
  • It means the person is trying to confuse the person doing maintenance a year down the road. Perhaps the programmer has *job security* issues – Ed Heal Mar 22 '12 at 15:42
  • Btw there are far more creative ways to crash the program. How about `for(char* ptr=0; true; ptr++) *ptr = 0xAA;` or `size_t max=0; max = ~max; while(malloc(max));` or `free((void*)&main);` or `int main(){return main();}.` (Stricly, some of them aren't allowed by C, but fun none the less. Don't try this at home.) – Lundin Mar 22 '12 at 15:49
  • @Ed heal: there is nothing wrong with this way of crawbar crashing. Sometimes one can have a reason not to call exit() _exit() or abort(). And there might be platforms/occasions where dereferencing the deadbeef pointer does not cause a crash/exception, so the third line *could* be useful after all. – wildplasser Mar 22 '12 at 15:59
  • @wildplasser - I disagree - code should be easy to understand from the outset. Why not just raise a signal on your own process - simple, easy to understand and effective. You can even get a debugger to catch them. Please tell me what reason for a convoluted method to be adopted? – Ed Heal Mar 22 '12 at 16:05
  • 1
    @Ed Heal: signals could be unavailable, masked, or unwanted. Maybe the macro has to be callable *from within* a signal handler. Who knows? BTW: if a debugger+watchpoints are available, setting a watchpoint on 0xdeadbeef will be a catch-all, and the stacktrace will hopefully do the rest. Also: using a dbugger, there is a possibility to jump out of this fragment and continue execution. You can't escape from an abort(). – wildplasser Mar 22 '12 at 16:30
  • I just think that the code is unreadable and there are better solutions that this convoluted method. I see that you have offered not a reasonable reason for doing this. – Ed Heal Mar 22 '12 at 16:33
  • 1
    Since you don't know the context (neither do I), you cannot prove that there is a better method. There could be. Or there could be not. Also: the above code is *not* unreadable. Even if you don't understand how it works, you can still read it, and know what it does (or is supposed to do). Do you understand your debugger's source code? – wildplasser Mar 22 '12 at 17:18
  • possible duplicate of [What does this C statement mean?](http://stackoverflow.com/questions/8249483/what-does-this-c-statement-mean) – Alexey Frunze Mar 22 '12 at 20:02
  • @BoBTFish OWBWebkit source. People may criticize the readability, but the macro name is clear enough. Might as well have some fun with forcing an app to crash:) – MM. Mar 23 '12 at 13:38

9 Answers9

14

It looks like it casts 0 as a function pointer (with the signature that it takes not parameters and has void return type) and then invokes it.

(     (            void(*)()                  ) 0       )      ();
  /* cast..*/ /* fn pointer signature */  /*..cast 0 */  /* invocation */

Which is another way to say that it's trying to invoke (call) a function that's expected to be located in memory at address 0x00000000 - which is guaranteed to be an invalid address.

Mike Dinescu
  • 54,171
  • 16
  • 118
  • 151
3
  • Cast 0 to a pointer to a void function that takes can be called with no parameters (the (void(*)())0 part of the expression)
  • Call that function through a pointer with an empty parameter list (the () part after it).

EDIT 1: Edited in response to Cristoph's comment.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    C vs C++ strikes again: in C++, an empty parameter list means the function takes no arguments; in C, that's only the case for definitions - in general, an empty parameter list means that the function takes an unspecified number of non-variadic arguments subject to default argument promotion – Christoph Mar 22 '12 at 15:31
  • @Christoph Darn it! Well, at least in this case fixing the answer required significantly less effort. – Sergey Kalinichenko Mar 22 '12 at 15:38
2

It casts 0 to a function pointer, where the function takes no argument and returns void, then tries to call this function. It basically dereferences a null pointer.

BoBTFish
  • 19,167
  • 3
  • 49
  • 76
2

It casts a NULL pointer to a method taking no parameters and returning void, and attempts to call this method.

Needless to say, it crashes, so the name CRASH suits it very well.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

It casts 0 to a pointer to a function, then attempts to call that function. Which will cause a segfault and crash.

Edit: way too much competition for these questions. Upvotes all round, and I'm going to bed :)

blueshift
  • 6,742
  • 2
  • 39
  • 63
0

It means “treating NULL pointer as pointer to void function(), call function()”.

hamstergene
  • 24,039
  • 5
  • 57
  • 72
0

It takes the value zero, and casts it to a function pointer that doesn't return anything (void).

Presumably, the purpose is that when you call this "function", it calls address zero, which should indeed crash the application.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
0

For me it is simpler to translate to a different C++, rather than directly to english:

typedef void (void_func_t)();       // type of a function taking no arguments 
                                    // and returning void
typedef void_fnct_t* void_func_ptr; // pointer to such a function
static_cast<void_func_ptr>(0)();    // call that function
// ((void_func_ptr)0)();            // pure C equivalent cast
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Won't the static cast throw an exception and prevent the program from crashing? – Lundin Mar 22 '12 at 15:39
  • @Lundin: `static_cast` **never** throws exceptions. **dynamic_cast** can throw exceptions, but it cannot be used with function pointers, and it will *only* throw when casting references. – David Rodríguez - dribeas Mar 22 '12 at 15:43
0

if fp is a pointer to a function, *fp is the function itself, so(fp)()is the way to invoke it. ANSI C permits this to be abbreviated as fp(), bu keep in mind that it is only an abbreviation. -------C traps an pitfalls. ( ( void()() )0 ) () is the avvreviation of ( ( void()() )0 )()