Uninitialized Pointers in Code

Uninitialized pointers in code

int* ptr = NULL; //Is this going to avoid the problem

This will cause ptr to point to NULL which you can explicitly check for as a default/uninitialized value. It prevents the problem you describe, but a careless programmer can still accidentally dereference a null pointer without checking, causing undefined behaviour.

The main advantage is your convenience for checking whether the ptr has or has not been initialized to anything, ie:

 if (ptr != NULL)
{
// assume it points to something
}

Since this is pretty idiomatic, its pretty dangerous to not initialize the pointer to NULL. The pointer would be initialized to a non-NULL garbage value that doesn't really point to anything real. Worst of all, the check above would pass, causing even worse problems if it just so happens that the address in the pointer is memory you can legally access. In some Embedded environments, you might be able to access any part of memory, so you might accidentally corrupt random parts of memory or random parts of your executing code.

what exactly is the danger of an uninitialized pointer in C

What does Trevor mean by "whatever was on the stack when the space for f was allocated"?

He means that in most assembly languages, separate instructions are used to reserve space on the stack and to write an initial value inside the newly reserved space. If a C program uses an uninitialized variable, the program will typically at run-time execute the instruction that reserves stack space but no instruction that sets it. When the pointer is used, it will literally contain the bit pattern that was on the stack before space was reserved. In the good cases this will be an invalid address. In the bad cases this will happen to be a valid address, and the effects will be unpredictable.

This is only a typical behavior. From the theoretical point of view, using an indeterminate value is undefined behavior. Much stranger things than simply accessing an invalid address or a valid one can happen (examples with uninitialized data (not addresses) used accidentally or purposely).


Here is the sort of dangers that a restricted subset of C such as Cyclone aims to prevent:

int a, *p;

int main(int c, char **v){
int l, *lp, i;
if (c & 1)
a = l + 1; // danger
if (c & 2)
*lp = 3; // danger
if (c & 4)
{
p = &a;
for (i=0; i<=1; i++)
{
int block_local;
*p = 4; // danger
p = &block_local;
}
}
}

In the last dangerous line, in practice, it is most likely that 4 will be written to variable block_local, but in reality, at the second iteration, p is indeterminate, the program is not supposed to access *p, and it is undefined behavior when it does.

Why uninitialized pointers cause mem access violations close to 0?

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.

Strange behavior with uninitialized pointers

In general, just don't use uninitialized variables at all. If you want to know more, read on.

All your examples are straight Undefined Behavior (UB), due to this standard passage:

6.3.2.1 Lvalues, arrays, and function designators


[...]

2 [...] If the lvalue designates an object of automatic storage duration that could have been declared with the register storage class (never had its address taken), and that object is uninitialized (not declared with an initializer and no assignment to it has been performed prior to use), the behavior is undefined.

Now, let's pretend in some omitted line the address was taken.

&i; // Like this

6.2.4 Storage durations of objects


5 An object whose identifier is declared with no linkage and without the storage-class
specifier static has automatic storage duration, as do some compound literals. [...]

6 [...] The initial value of the object is indeterminate.

Alternative quote:

6.7.9 Initialization


[...]

10 If an object that has automatic storage duration is not initialized explicitly, its value is
indeterminate.

3.19.2


1 indeterminate value
either an unspecified value or a trap representation

3.19.3


1 unspecified value
valid value of the relevant type where this International Standard imposes no
requirements on which value is chosen in any instance

2 NOTE An unspecified value cannot be a trap representation.

3.19.4


1 trap representation
an object representation that need not represent a value of the object type

6.2.6.1 General


5 Certain object representations need not represent a value of the object type. If the stored
value of an object has such a representation and is read by an lvalue expression that does
not have character type, the behavior is undefined. If such a representation is produced
by a side effect that modifies all or any part of the object by an lvalue expression that
does not have character type, the behavior is undefined.50) Such a representation is called
a trap representation.

Thus, if your implementation supports trap-representations for the type you read (Yours don't for int*), you have UB.

Because you don't, unspecified value applies, which means every read returns some arbitrary value, and not neccessarily the same.


All quotes are from draft n1570, C99+Ammendments aka C11.

uninitialized pointer of structure to the function

If you do not want to allocate the pointer in the main function, you have two possible solutions:

Solution 1

Do not pass the healthcare_table pointer to the load_healthcare_table() function, but rather return the initialized pointer from the function itself. Something along these lines:

int main() {
healthcare_table *records;
int step = 1;
records = load_healthcare_table(&step);
return 0;
}

In this case your load_healthcare_table() function would be:

healthcare_table* load_healthcare_table(int* step) {
healthcare_table *table;
table = (healthcare_table*)malloc(sizeof(healthcare_table));
// Fill table here
return table;
}

Important note
In this case make sure you do not create the table locally to the load_healthcare_table() function. This would destroy the table once the function returns, resulting in garbage data. A function should never return a pointer to its local data. So the following example would be wrong:

healthcare_table* load_healthcare_table(int* step) {
healthcare_table table;
// Fill table here
return &table;
}

Solution 2

Pass a pointer to a pointer of the healthcare_table to the function load_healthcare_table(). It would look something along these lines:

int main() {
healthcare_table *records;
int step = 1;
load_healthcare_table(&records,&step);
return 0;
}

In this case, the load_healthcare_table() function will be:

void load_healthcare_table(healthcare_table** t, int* step ) {
*t = (healthcare_table*)malloc(sizeof(healthcare_table));
// Fill table here
}

EDIT

As suggested by Ajay Brahmakshatriya: Sticking to standard C notion of local variables rather than going into stack terminologies.

Is there a use for uninitialized pointers in C or C++?

This is a very specialized optimized case for Video Games (basically an embedded system). We used to use them for Load-In-Place data behavior in our Video Games to speed up loading (and avoid fragmentation).

Basically we would create console-side (Playstation) objects in a PC cooker. Then to reduce fragmentation overload, we would pack the data objects in a contiguous buffer with a single alloc. References to the data objects in this buffer would then be changed to subtract the base from pointers to offsets (unfix call -- we also had a virtual fix / unfix calls that took the buffer base and could convert between offsets and pointers).

When we loaded the data, it loaded in one large block. All data referenced by the root was off the root object. We could do an inplace "new" on the the root that would initialize the proper VF tables for the object and fixup all the attached blocks (by doing inplace new and then fixing up attached blocks respectively).

We needed the constructors called (in place new) to generate the proper VF-Tables in the objects. However, if the pointers were automatically cleared to NULL during the constructor, we would have lost the offset data and not been able to recreate the pointers between the objects within the contiguous block.


FWIW, this is a common technique in the Video Game world. This Gamasutra article (not written by me or my coworkers) explains in detail the similar thing they did at another company:

Also, this topic of discussion on SourceForge.

There have even been several GDC (Game Developer Conference) talks on the subject.

Searching on Google for "load-in-place" will give many other examples of people using this technique that basically requires uninitialized pointers.


NOTE: Currently, this is the only response that actually answers the question asked ("Is there a use for uninitialized pointers in C or C++?") by giving a specific use for pointers that must remain unitialized.

All the other responses are better answers for the original question referenced ("[C++] Why aren’t pointers initialized with NULL by default?") that caused the poster to ask this question.



Related Topics



Leave a reply



Submit