Dereferencing a pointer to 0 in C

CPointersMemoryDereference

C Problem Overview


Sometimes data at memory address 0x0 is quite valuable -- take x86 real mode IVT as a more known example: it starts at 0x0 and contains pointers to interrupt handlers: a dword at 0x00 is a pointer to division by zero error handler.

However, C11 language standard prohibits dereferencing null pointers [WG14 N1570 6.5.3.2], which are defined as pointers initialized with 0 or pointers initialized with a null pointer [WG14 N1570 6.3.2.3], effectively banning the very first byte.

How do people actually use 0x0 when it's needed?

C Solutions


Solution 1 - C

C does not prohibit dereferencing the null pointer, it merely makes it undefined behavior.

If your environment is such that you're able to dereference a pointer containing the address 0x0, then you should be able to do so. The C language standard says nothing about what will happen when you do so. (In most environments, the result will be a program crash.)

A concrete example (if I'm remembering this correctly): On the 68k-based Sun 3 computers, dereferencing a null pointer did not cause a trap; instead, the OS stored a zero value at memory address zero, and dereferencing a null pointer (which pointed to address zero) would yield that zero value. That meant, for example, that a C program could treat a null pointer as if it were a valid pointer to an empty string. Some software, intentionally or not, depended on this behavior. This required a great deal of cleanup when porting software to the SPARC-based Sun 4, which trapped on null pointer dereferences. (I distinctly remember reading about this, but I was unable to find a reference; I'll update this if I can find it.)

Note that the null pointer is not necessarily address zero. More precisely, the representation of a null may or may not be all-bits-zero. It very commonly is, but it's not guaranteed. (If it's not, then the integer-to-pointer conversion of (void*)0 is non-trivial.)

Section 5 of the comp.lang.c FAQ discusses null pointers.

Solution 2 - C

> How do people actually use 0x0 when it's needed?

By either:

  • writing the required code in assembly language, or
  • writing the code in C and verifying that their compiler generates correct assembly language for the desired operation

Solution 3 - C

The statement:

char * x = 0;

does not necessarily put 0x0 into x. It puts the defined null pointer value for the current architecture and compiler into x.

Now, in practical terms, all compilers / processors observed in common use do end up putting 32 (or 64) 0 bits in a row in a register or storage location in response to that statement, so, so if memory address 0 is useful, then, as others have indicated, you are stuck using formally undefined behavior. However, in once upon a time there was hardware out there for which a 'null pointer' was some bit pattern that was not all zeros, and, who knows, there may be again.

Solution 4 - C

Annex J It is undefined behavior when...

> The operand of the unary * operator has an invalid value (6.5.3.2).

In that same footnote you mentioned, it says a null pointer is an invalid value. Therefore, it is not prohibited, but undefined behavior. As for the distinction between address 0x0 and a null pointer, see Is memory address 0x0 usable?.

> The null pointer is not necessarily address 0x0, so potentially an > architecture could choose another address to represent the null > pointer and you could get 0x0 from new as a valid address. > > Whether the null pointer is reserved by the Operative System or the > C++ implementation is unspecified, but plain new will never return a > null pointer, whatever its address is (nothrow new is a different > beast). So, to answer your question: > > > Is memory address 0x0 usable? > > Maybe, it depends on the particular implementation/architecture.

In other words, feel free to use 0x0 if you're sure on your system that it won't cause a crash.

Solution 5 - C

The operating system use a table of pointers to interrupt routines to call appropriate interrupt(s). Generally (in most operating system) table of pointers is stored in low memory (the first few hundred or so locations), These locations hold the addresses of the interrupt service routines for the various devices.

So when you do

char *ptr = 0x0; 

then most likely you are initializing your pointer with the address of an interrupt service routine. Dereferencing (or modifying) a memory location which belongs to operating system most likely cause program to crash.
So, better not to initialize a pointer to 0x0 and dereference it until you have the confirmation that it doesn't belongs to OS.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestiongfvView Question on Stackoverflow
Solution 1 - CKeith ThompsonView Answer on Stackoverflow
Solution 2 - CGreg HewgillView Answer on Stackoverflow
Solution 3 - CbmarguliesView Answer on Stackoverflow
Solution 4 - Cuser1508519View Answer on Stackoverflow
Solution 5 - ChaccksView Answer on Stackoverflow