I’m going to try to make a contribution from a hardware point of view.
All modern operating systems use “virtual memory” (which is very different from “virtual machines”) to allocate storage to processes. When you run an application (whether written in C, or Basic, or assembly language), it is loaded into the virtual memory space of a process. For the purposes of this discussion, I’m going to ignore the issues caused by paging, working sets, and other features that implement the virtual memory, and concentrate on the features of virtual memory from the application’s side.
Each application has its own “memory space”, or “address space.” That range of addresses can be huge: with a 32-bit operating system, it is theoretically 4 GB (4,374,659,072 bytes) - and again, I’m going to ignore issues such as the 3.7 GB limit in Windows. With a 64-bit operating system, the address range is (theoretically) 19,137,641,996,231,901,184 bytes. However, a program doesn’t actually use that entire address space; instead, it has sections of the address space allocated form code, data, stack, etc. The technical name for each of the sections is “segment.”
The hardware mechanisms that implement the virtual memory use the segment definitions to determine which parts of the virtual address space are in use. When an application attempts to access an address that is not in one of the defined segments, the hardware generates a segment fault.
I’m not going to get tangled up in the discussion of what constitutes a “dangling pointer,” except to say that it very rare that a dangling pointer by itself is going to generate a segment fault. You see, regardless of whether the object is still there or not, the point is still pointing at a memory location that is within one of the existing segments - the object was allocated at a legitimate address, and the pointer is still pointing to that address.
However, let’s look at what happens when a pointer is a reference to an object or structure which in turn contains pointers (the object or structure references other variables). Now we have a dangerous situation. The object is deleted, and the memory allocated to it is reused, filling that space with some random data. Then, the dangling pointer is used to refer to that space, and some part of the space is used as a pointer. Because that space has been overwritten, the value may (note I wrote may, not will) be an address that is outside of any segment assigned to the process. That is what causes a segment fault.
There is another way that you can get a segment fault, but this typically affects only one segment: the one used to hold the stack. A stack, which is a first-in, last-out storage area, grows from a starting location, towards some other location. The segment that is used for the stack is allocated so that one end of the allocation is the starting point of the stack, and the other end of the segment allocation is the maximum size of the stack.
Now, if the stack grows bigger than that maximum size, the stack pointer is pointing outside the allocated space. That is a segment fault. But, for this one segment, that segment fault is reported as a stack overflow, because that is a much more informative error message - but a stack overflow is (in most operating systems) always detected as a segment fault.
Different operating systems (Windows, OS-X, *nix, etc.) have different ways to set up the segmentation controls. Different processors (Intel x86, IBM PowerPC, Sun SPARC) have different hardware implementations of segmentation. With all these variations, the names of the procedures, and the names of the data elements that go into each segment’s description, vary all over the lot. I don’t see any reason to get caught up in attempts to identify the specifics of these features (also, I don’t know the specifics for most systems or most processor types); if you’re really concerned about these issues, remember that The Help File Is Your Friend: find the manuals for your environment and study them.
Michael S. Meyers-Jouan