Monday, January 2, 2006

Why do I get an AV when accessing a pointer (including a PChar) or object?

In the following discussion, the term pointer is used to generically refer to variables of explicit pointer types, PChars and objects. This was written from a Delphi perspective, but the techniques are generally applicable.

Remember, declaring a variable of any pointer type only allocates 4 bytes for the pointer. The pointer does not refer to anything. Before it can be referenced, it must be assigned a value. Depending on context, the pointer's value may come from any number of sources, including: memory allocation routines, a return value from a function, a constant, a variable or, in the case of objects, the constructor method. Not performing this step is a sure way to AV. Always check the return value of memory allocation functions to verify that the pointer was assigned a valid value.

Another way to AV sometimes is to access a pointer whose contents have already been freed. Depending on many factors, sometimes this will work and sometimes it will AV. This is especially easy to do if the variable's scope is greater than the current procedure. One good practice, particularly when variables have an object or global scope is to set their value to nil immediately after freeing it. No, this is not automatically done. If nothing else, following this practice will eliminate the "sometimes" nature of the problem.

Assuming the pointer has been assigned a valid value and it has not been freed, the final item to check is the value of the pointer when the AV occurs. If it is the same value, then the memory is being referenced (possibly through a typecast) incorrectly. Accessing a freed object can cause this too. If it is a different value, then the next task is to track down why. Probably something else in the program is accessing memory incorrectly, not causing an AV but corrupting this pointer. On cause of this is writing to array elements outside the bounds of the array. Turn on the range checking option to help determine if this is happening.

There are several ways to find this. 1) Do a very careful code review until the offending code is found. 2) Establish breakpoints between the time the value is correct and when it is bad with a watch on the pointer that's being changed. 3) Remove code between creation and known corruption until the problem goes away. 4) Use a tool that detects memory overwrites.

No comments: