13

So the line of code in question is:

*((int*)(0))=1;

Because I have so little experience with C/C++ and haven't tried very hard, I don't understand this simple expression. What does it mean exactly?

cgf
  • 3,369
  • 7
  • 45
  • 65

5 Answers5

29

It's meant to crash the program, typically useful during debugging.

It'll dereference the NULL pointer and attempt to assign a value to that memory, which is theoretically just undefined behavior, but will result in an access violation exception on 99% of systems.

Typically, it's found in cases such as:

if ( !FileRead(importantFile) )
{
    // this should never happen, critical exception
    *((int*)(0))=1;
}
Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • 6
    Well, how is it better than `exit(EXIT_FAILURE);`. While debugging (with `gdb`) it will show the message *The eprogram exited with exit code [EXIT_FAILURE]*. – 0xF1 Aug 01 '14 at 08:59
  • 1
    @Don'tYouWorryChild Read the first sentence. Exiting will leave no trace behind. – Jim Balter Aug 01 '14 at 09:00
  • @Don'tYouWorryChild "it will show the message" and what good is that? – Jim Balter Aug 01 '14 at 09:01
  • @JimBalter : Well, why not end program gracefully, why need to crash it, what better purpose does that serve. – 0xF1 Aug 01 '14 at 09:01
  • 3
    @Don'tYouWorryChild **Read the first sentence.** Do you really have no idea what the purpose of a debugger is? The "better purpose" is to be able to access memory and variables and a stack trace. – Jim Balter Aug 01 '14 at 09:02
  • @JimBalter : Ok, got your point, that way it will be easy to backtrack. – 0xF1 Aug 01 '14 at 09:02
  • 11
    @Don'tYouWorryChild It will produce a stack backtrace, whether in the debugger or core dump or whatever. But, `raise()` is the better choice. – Potatoswatter Aug 01 '14 at 09:03
  • @Potatoswatter : Ya, got that!! – 0xF1 Aug 01 '14 at 09:04
  • 11
    Exiting in a debugger-friendly way has a name: `abort()`. About OP's question, it's undefined behaviour to assign something to the NULL pointer; therefore, the compiler is allowed to deduce that that line of code leads to undefined behaviour and optimize it out altogether. – peppe Aug 01 '14 at 09:11
  • @peppe correct (ergo the 99% :) On debug builds, I've never seen this happen, which is where most debugging takes place. – Luchian Grigore Aug 01 '14 at 09:25
  • I wonder if making the type `volatile int*` would help as a remedy against those modern annoyingly broken-on-purpose ("super smart") compilers. – Damon Aug 01 '14 at 09:58
  • @Damon we have standards for a reason, if you don't follow them then it is your code that is broken, not the compiler. – M.M Aug 02 '14 at 13:30
  • @MattMcNabb: The reason, however, is not an excuse for being a total dickhead, as is the case with some recent implementations. Programming language and compiler are tools which are to help the programmer implement a software. They are to work for the human, not against him, and they are not a purpose in themselves. There is no benefit in deliberately breaking an otherwise good program based on "Oh, here is some unrelated UB around", which is what is currently becoming "fashion". Contrary to a well-known web comic, UB does **not** mean that demons have to (or _should_) fly out of your nose. – Damon Aug 03 '14 at 10:46
  • 1
    If it makes conforming programs run faster then it is a benefit. For example, in a tight loop omitting a check which can never be true if the program is conforming. gcc lets you go -O2 if you want "get away with some UB" mode, and -O3 if you want "super fast mode if your program conforms". – M.M Aug 03 '14 at 10:48
12

Break it down piece by piece. Inside the outer brackets on the left, you have:

(int*)(0)

This is a C-style cast of the value 0 to a pointer to int; creating a null pointer, in effect.

Let's add a variable to capture the result of this first expression:

int* x = (int*)(0);

The outer part is now:

*(x) = 1;

This is dereferencing the pointer x, and assigning 1 to the resulting int.

Since (in this case) x is a null pointer, this will crash on dereference (strictly speaking, it will crash on the assignment following the dereference - see comments below). It's typically used to force a crash or other system-dependent undefined behaviour; usually for testing or debugging purposes. You wouldn't want a line like this in your production code.

Note: There are some architectures, usually in embedded systems, where zero is a valid memory address, and the code above may have a legitimate purpose. However, if you were working on such a platform, it is unlikely that you would struggle with the syntax in the question.

Andrew
  • 5,212
  • 1
  • 22
  • 40
  • 1
    It will not necessarily crash on dereference. While it is the dereferencing of the null pointer that yields undefined behavior, the crash usually occurs one step later in the write access during the assignment. – Arne Mertz Aug 01 '14 at 09:03
  • 1
    A "dereference" on the LHS doesn't actually access memory, and can't be separated from the assignment, which does. – Jim Balter Aug 01 '14 at 09:08
  • Well yes, at an implementation level, dereferencing the pointer just provides a zero to be used as the argument to an instruction that actually reads or writes. It is that instruction that will fail. – Andrew Aug 01 '14 at 09:52
9

As others have noted, it's a way to drop into the debugger. Most computers will refuse to write to memory address 0 and will enter some kind of diagnostic mode instead.

However, a better alternative is the standard function raise(), from <signal.h> or <csignal>. raise( SIGSEGV ) will produce the same result as your example intends to, even on computers that do allow writing to address zero (such machines do exist!) and compilers with liberal interpretation of undefined behavior. That operation is not guaranteed or required to crash. From the compiler's perspective it might as well do nothing, and it would not be incorrect to simply delete it from the compiled program.

For a more descriptive signal value, see man signal. What is meant is probably raise( SIGTRAP ), or abort(). The latter is equivalent to raise( SIGABRT ) on my system, but I'm lazy to check whether that equivalency is guaranteed by POSIX or the C language.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421
  • 1
    See also http://stackoverflow.com/questions/173618/is-there-a-portable-equivalent-to-debugbreak-debugbreak – Suma Aug 01 '14 at 09:22
  • What machines allow writing to address zero? Are these mainly embedded devices? I thought this depended on the OS (where applicable) and how it maps the address space? – Charles Aug 01 '14 at 09:42
  • 1
    @wrtmu Right. Any system with virtual memory can simply arrange for zero to be writable. Those without virtual memory (which are usually embedded) might have interrupt vectors there. I cut my teeth on the "classic" Mac OS, which was originally designed with no virtual memory. The first four bytes were unused IIRC; after that came interrupt handlers. Accidentally spraying data there brought down the machine. – Potatoswatter Aug 01 '14 at 09:46
2

This stores something at null pointer (and causes SEGFAULT). Useful for stopping the program and calling debugger while preserving all memory contents etc.

Tõnu Samuel
  • 2,877
  • 2
  • 20
  • 30
2

This *((int*)(0))=1;is equal to

int *p=NULL;
*p=1;
mahendiran.b
  • 1,315
  • 7
  • 13