Why uninitialized pointers cause mem access violations close to 0?
Asked Answered
C

3

5

It is said that often (but not always) when you get an AV in a memory location close to zero (like $89) you have an uninitialized pointer.
But I have seen this also in Delphi books... Hm... or they have been all written by the same author(s)???


Update:
Quote from "C++ builder 6 developers guide" by Bob Swart et all, page 71:

When the memory address ZZZZZZZZZ is close to zero, the cause is often an uninitialized pointer that has been accessed.

Why is it so? Why uninitialized pointers contain low numbers? Why not big numbers like $FFFFFFF or plain random numbers? Is this urban myth?

Cyclostome answered 7/2, 2019 at 9:39 Comment(8)
"it is said" is a bit generic. Can you link to some resources stating that?Draftsman
Uninitialized means the variable contains an undetermined value. Period. Undetermined is undetermined, it can be anything.Fineable
Area of global variables is initialized by zeros, so initial value for global pointers is zero. Local variables might have any value.Infuriate
@Draftsman - C++ builder 6 developers guide by bob swart et all, page 71Cyclostome
@Draftsman - And many many many other places. I heard that 30 times by now. It is quite a wonder you haven't heard it by now. EVEN if this proves to be urban legend.Cyclostome
Never heard that before (although I do see the reasoning behind it), which is why I asked for references ;)Draftsman
Note most compilers in debug mode quietly preset unset values to hex values CDCDCDCD or something similar. Your case is use of pointer which points to nothing, which is usually a nullptr equal zero.Tardif
The rule is one way: Low addresses are a sign of uninitialized pointers. That doesn't imply the reverse, that all uninitialized pointers are at low addresses. It is simply that valid pointers on the heap or stack have usually higher values. That also doesn't imply that high addresses are a sign of proper initialized pointers.Salami
S
13

This is confusing "uninitialized pointers" with null references or null pointers. Access to an object's fields, or indexes into a pointer, will be represented as an offset with respect to the base pointer. If that reference is null then the offsets will generally be addresses either near zero (for positive offsets) or addresses near the maximum value of the native pointer size (for negative offsets).

Access violations at addresses with these characteristic small (or large) values are a good clue that you have a null reference or null pointer, specifically, and not simply an uninitialized pointer. An uninitialized reference can have a null value, but may also have any other value depending on how it is allocated.

Shipping answered 7/2, 2019 at 10:7 Comment(11)
You can possibly add that some compilers will initialise "uninitialised" memory, to aid in exactly this sort of post-mortem analysisBionomics
@Bionomics A complete breakdown of memory allocation implementation details for all the modes and platforms of all possible compilers for delphi and C++ would not fit in this answer, I think.Shipping
My sincerest apologies - I misread this answer and downvoted it. Now converted to an upvote. For me this seems like a very plausible explanation.Monafo
The quote from the book referenced in the comments specifically mentions uninitialized pointer rather than offset from a nil pointer.Heavyset
@DavidHeffernan I don't think it changes the answer. The quote from the book suffers from the same misconception, I think. The only caveat I can think of was mentioned briefly in a (now deleted) comment, and that surrounds the statistical distribution of values in stale memory. I think that discussion is a valid extension to this answer, but to first order I think this is primarily a confusion about the difference between a null value and an uninitialized value.Shipping
I think that the point is that it's not so much the asker that is confusing things, but more likely the author of the quote. Of course, the fact that the asker failed to reference the quote is pretty unhelpful.Heavyset
@DavidHeffernan I'm still not sure what you're getting at. Would you like me to replace the word "You" at the beginning of my answer with something else? How about this?Shipping
Yes, I think that's better. I think that the asker has been misled by a poor piece of writing in the referenced textHeavyset
@DavidHeffernan The lengths I sometimes go to to placate your OCD, I swear, lol. You're welcome ;)Shipping
@Shipping - Ok, so " If that reference is null then..." has a very important role into this equation.Cyclostome
added exact quote from the book.Cyclostome
H
7

Why uninitialized pointers contain low numbers?

They don't. They can contain any value.

Why not big numbers like $FFFFFFF?

They can perfectly well contain values like $FFFFFFF.

or plain random numbers?

Uninitialised variables tend not to be truly random. They typically contain whatever happened to have been written to that memory location the last time it was used. For instance, it is very common for uninitialised local variables to contain the same value every time a function is called because the history of stack usage happens to be repeatable.

It's also worth pointing out that random is an often misused word. People often say random when they actually mean distributed randomly with uniform distribution. I expect that's what you meant when you used the term random.

Heavyset answered 7/2, 2019 at 9:50 Comment(5)
Uninitialized is UB, not random. Particularly significant in the context of optimizations.Reichel
@PasserBy I explicitly said not randomHeavyset
I apparently used the wrong words. I meant they don't hold any value. They are undefined.Reichel
@PasserBy That's not what undefined means. They definitely hold a value, there is just no guarantee about what that value is.Shipping
@PasserBy: an uninitialized pointer or integer will most definitely contain a value. Just not necessarily a valid or useful one.Judas
M
5

Your statement about AV close to zero is true for dereferencing a null pointer. It is zero or close to zero because you either dereference the null pointer:

int* p{};
const auto v = *p; // <-- AV at memory location = 0

or access an array item:

char* p{};
const auto v = p[100]; // <--AV at memory location = 100

or a struct field:

struct Data
{
  int field1;
  int field2;
};

Data* p{};
const auto v = p->field2; // AV at memory location = 4
Mandi answered 7/2, 2019 at 10:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.