The examples are given in terms of COBOL pointers. However, the same ideas are mostly valid wherever you use pointers (or even simulate them by using table subscripts or other gimmicks).
This blunder will cause an abend. Always check for NULL before dereferencing a pointer.
Until you initialize it, a pointer will be NULL, or it will contain garbage pointing to a random location in memory. Dereferencing it will cause an abend -- if you're lucky.
Whenever you declare a pointer in WORKING-STORAGE, always initialize it to NULL with a VALUE clause. Then your code has a way to defend itself. It can detect NULL, but it cannot detect garbage.
Likewise: if you dynamically allocate something which contains a pointer, set the pointer to NULL or to some other reasonable value as soon as you allocate it.
For example, you might MOVE SPACES to a group item which contains a pointer variable. The compiler won't protect you -- it will happily trash your pointer.
The only defense against this one is vigilance.
You may be juggling pointers to several kinds of objects. If you have a pointer to a USOC node, you'd better dereference it to a USOC node. If you dereference it to a FID node, bad things will happen.
In C or C++ the compiler gives you some protection against this problem, but not in COBOL. You just have to be careful, though naming conventions can help.
Let's say you have a perfectly good pointer to the first node in a linked list. Then you overlay the value of that pointer with another perfectly good value.
That sounds okay -- you're replacing one valid pointer value with another. But what happens to the linked list? Unless you kept another copy of the original pointer, the original list is gone. The memory it occupies still belongs to you, taking up space, but you have no way to use it. Before long you can lose vast tracts of memory this way. Even if you don't run out of memory and abend, you place a needless burden on the operating system.
Again, the only defense is vigilance. Whenever you overlay a pointer value, consider what you should do with the old value. If you're through with a piece of memory, either deallocate it or make some provision to reuse it later.
Consider the previous example again. Before you overlay the pointer, you deallocate the node to which the old value points.
That's some improvement. However, that node contained a pointer to the second node. Now that second node is lost, and all the rest of the list.
Solution: before you deallocate the first node, make a temporary copy of the pointer to the second node. Then deallocate. Repeat until done.
Let's say you have declared SOME-THING as an 01-level in the LINKAGE SECTION, and you intend to use it to dereference a pointer. But you get careless. Before dereferencing, you MOVE SPACES TO SOME-THING. Oops. Abend.
(You can't make this mistake in C. The syntax for C pointers gives you no way even to try.)
Once you deallocate a chunk of memory, you should treat it as gone forever. But if you still have a pointer to it lying around, you might accidentally try to access it through that pointer. The results are unpredictable but may include the following:
You can minimize this danger if, whenever you deallocate something, you set the corresponding pointer to NULL. That way (if you follow the advice given earlier) you won't even try to dereference it.
Even if you follow this policy, you are still vulnerable whenever you have multiple copies of the same pointer. You might nullify one copy but try to use the other.
As a result, you should avoid keeping multiple copies of pointers. When you can't avoid it, control the extra copies carefully. Designate only one of the copies to be used for deallocation.
If you're really paranoid, corrupt the entire object just before deallocating it. Move SPACES to it, or HIGH-VALUES, or something. If you accidentally access it later, at least you're not likely to mistake it for a valid object. Your mistake will be more visible.
This is a special case of the previous mistake. Similar precautions apply.
Not every pointer points to something you can deallocate. It might point to some item in WORKING-STORAGE somewhere, or to the inside of an allocated object, or to garbage. Deallocating with such a pointer leads to surprises.
If you build your data structures incorrectly, later operations on them won't work right. For example, if you accidentally turn a linked list into a circular list, an attempt to search the list may lead to an infinite loop. Neither the compiler nor the operating system can have any idea what your data structures are supposed to look like. They can't protect you -- except by abending, eventually, in the case of an infinite loop.
One reason for this pitfall is that a given pointer points to different things at different times, and an entry in the LINKAGE SECTION represents different objects at different times. It's easy to lose track of what's what.
To reduce the hazards, confine your pointer operations to short, well-encapsulated segments of code. So far as possible, each such segment should assume no more than is necessary about the prior values of whatever variables it uses. Resist the temptation to save a few machine cycles by reusing some values that you think will be left over from a previous operation.
This one is subtle, and you may never encounter it, but it can happen. So don't say we didn't warn you.
Suppose you have a list of nodes, each of which contains some number. You want to accumulate a total in the last node. So you set up two nodes in the LINKAGE SECTION:
01 THIS-NODE.
05 THIS-NEXT-NODE USAGE IS POINTER.
05 THIS-COUNT PIC S9(7) COMP.
01 TOTAL-NODE.
05 TOTAL-NEXT-NODE USAGE IS POINTER.
05 TOTAL-COUNT PIC S9(7) COMP.
You dereference the appropriate pointers to locate THIS-NODE and
TOTAL-NODE:
SET ADDRESS OF THIS-NODE TO FIRST-NODE-P.
SET ADDRESS OF TOTAL-NODE TO LAST-NODE-P.
For each node in the list you execute the following:
ADD THIS-COUNT TO TOTAL-COUNT.
MOVE ZERO TO THIS-COUNT.
Looks good, right? Imagine your chagrin when you discover that the
total is always zero.
When you reach the end of the list, THIS-NODE and TOTAL-NODE are the same object. Hence THIS-COUNT and TOTAL-COUNT are two different names for the same variable, and the last MOVE ZERO undoes all your work.
Okay, so it's a contrived and artificial example. It's not easy to come up with a realistic example. The point is that whenever you have two instances of the same kind of object in the LINKAGE SECTION, you must remember that they can potentially be the same object. This possibility defies all our intuition, but it can happen.
(Aliasing is not confined to the use of pointers. Even in an ordinary CALL, you can pass the same thing as two different parameters.)