7

I was wondering... what if when you do a new, the address where the reservation starts is 0x0? I guess it is not possible, but why? is the new operator prepared for that? is that part of the first byte not usable? it is always reserved when the OS starts?

Thanks!

Mario Corchero
  • 5,257
  • 5
  • 33
  • 59

4 Answers4

12

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. (I don't think anyone does that, btw, it would break the logic behind tons of memset calls and its just harder to implement anyway).

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.

K-ballo
  • 80,396
  • 20
  • 159
  • 169
  • Are you sure about that? Is the following code wrong? int * p = new( std::nothrow ) int; if( !p ) { ... } – Peter Ruderman Jan 18 '13 at 21:51
  • @PeterRuderman: Why would that code be wrong? Have you read the note about _nothrow `new`_ in my answer? – K-ballo Jan 18 '13 at 21:52
  • Well, the intent of the if is to check if p is non-null. But isn't it assuming that the null pointer is equivalent to 0? – Peter Ruderman Jan 18 '13 at 21:54
  • @PeterRuderman: No, it doesn't. It's checking whether the pointer is different from the _null pointer_. `!p` is the same thing as `p != 0` and a _literal 0_ is convertible to the _null pointer_, whatever its address is – K-ballo Jan 18 '13 at 21:55
  • So you're saying that on some architectures, the following expression could be false? p == 0 && reinterpret_cast( p ) != 0 – Peter Ruderman Jan 18 '13 at 21:58
  • @PeterRuderman: No, but this could be false: `p == 0 && reinterpret_cast( p ) != 0`. Also this one could be true: `p == 0 && p == (void*)0x12345678`! – K-ballo Jan 18 '13 at 22:00
  • 1
    Yes, `p == 0 && reinterpret_cast( p ) != 0` is permitted to be false. The mapping via `reinterpret_cast` from addresses to integers is implementation-defined, and a null pointer does not have to map to 0. For that matter, `reinterpret_cast(strlen("")) == (void*)0` can be false, because the special rule that says a *null pointer constant* must convert to a null pointer doesn't apply to all integer values equal to 0, only to integer constant expressions with value 0. – Steve Jessop Jan 18 '13 at 23:16
  • The reason is that pointer -> integer -> pointer must restore the original value, but the same is not required of integer -> pointer -> integer. That's why a null pointer is permitted to convert to some integer value other than 0, provided of course that this other value converted back to pointer gives a null pointer. Likewise a 0 that isn't an i.c.e can convert to some pointer value other than null. All this is very unusual, but not forbidden. If you imagine hadware where address 0 is somehow special (an I/O port or a register), the implementation might not want to use it for null. – Steve Jessop Jan 18 '13 at 23:24
  • @SteveJessop It's fairly unusual today, but in the past, there have been a number of widespread machines where null pointers weren't all 0 bits. (Prime and Honeywell, amongst others, if my memory serves me right.) And interestingly enough, in pre-standard days, most Unix implementations made page 0 write protected, but filled with 0's, so you could dereference a null pointer (but not write through it); many (very) early C programs used `NULL` for an empty string (`""`). – James Kanze Jan 19 '13 at 01:12
3

"Early" memory addresses are typically reserved for the operating system. The OS does not use early physical memory addresses to match to virtual memory addresses for use by user programs. Depending on the OS, many things can be there - the Interrupt Vector Table, Page table, etc.

Here is a non-specific graph of layout of physical and virtual memory in Linux; could vary sligthly from distro to distro and release to release:

http://etutorials.org/shared/images/tutorials/tutorial_101/bels_0206.gif

^Don't be confused by the graphic - the Bootloader IS NOT in physical memory... don't know why they included that... but otherwise it's accurate.

PinkElephantsOnParade
  • 6,452
  • 12
  • 53
  • 91
2

I think you're asking why virtual memory doesn't map all the way down to 0x0. One of the biggest reasons is so that it's painfully obvious when you failed to assign a pointer - if it's 0x0, it's pointing to "nothing" and always wrong.

Of course, it's possible for NULL to be any value (as it's implementation-dependent), but as an uninitialized int's value is 0, on every implementation I've seen they've chosen to keep NULL 0 for consistency's sake.

There are a whole number of other reasons, but this is a good one. Here is a Wikipedia article talking a little bit more about virtual addressing.

Matt
  • 10,434
  • 1
  • 36
  • 45
  • 1
    In fact, in MSVC debug builds, the memory behind most addresses in the low range is filled with a specific pattern so it's easier to detect wrong pointer operations. – lethal-guitar Jan 18 '13 at 21:42
  • 1
    @lethal-guitar: I know they do that with uninitialized memory, and out of bounds memory, but I'm pretty sure they _dont_ do that with low range addresses. – Mooing Duck Jan 18 '13 at 21:47
  • Hmm, maybe I'm wrong, but I think they do - so if you have a pointer to an object and it's a NULL pointer for some reason, trying to access a member will be 0+something, and by filling the pattern there, it's easy to detect as well. But yeah, I'm not 100% sure.. – lethal-guitar Jan 18 '13 at 21:54
  • @Matt The bootloader certainly is in physical memory, at least when you're booting. A lot of systems, especially those with small address spaces, will remap the addresses corresponding to the bootloader once they've finished loading, but this isn't necessarily the case. – James Kanze Jan 19 '13 at 01:14
  • @lethal-guitar Most modern VM based systems will simply leave the first page of your address space unmapped, so you the program will trap if you try to access it. It's not filled with anything, since it's simply not there. – James Kanze Jan 19 '13 at 01:19
1

Many memory addresses are reserved by the system to help with debugging.

0x00000000 Returned by keyword "new" if memory allocation failed

0xCDCDCDCD Allocated in heap, but not initialized

0xDDDDDDDD Released heap memory.

0xFDFDFDFD "NoMansLand" fences automatically placed at boundary of heap memory. Should never be overwritten. If you do overwrite one, you're probably walking off the end of an array.

0xCCCCCCCC Allocated on stack, but not initialized

But like a few others have pointed out, there is a distinction between physical memory addresses which is what the OS uses, and logical memory addresses which are assigned to your application by the OS. Example image shown here.

Porkbutts
  • 924
  • 7
  • 12
  • 1
    `new` throws an exception if allocation failed. – Luchian Grigore Jan 18 '13 at 21:52
  • sorry I was thinking malloc not new. – Porkbutts Jan 18 '13 at 22:35
  • @Porkbutts And `malloc` returns a null pointer, which isn't necessarily `0x00000000`. All of the others are very system specific; on most systems, at least when optimization is active, uninitialized memory can be anything, and released heap memory retains its last values. – James Kanze Jan 19 '13 at 01:21