Toby Ewing wrote:
I'm having trouble with list management again.
The code snipper below is part of a much longer program. It crashes apparently at random, sometimes after looping several thousand times. A simplified version ran "forever", so I know the basic strategy is fine. The crash occurs upon "dispose"ing a record in list Root, and gives sometimes a Page Fault, sometimes a General Protection Fault. Examining the record being disposed shows no pattern, such as being at the end of the list, near the edge of the lattice, etc.
... snip ...
It's probably an obvious problem, and I'm hoping fresh eyes can see it.
All I have done below is reformat, so I could follow it, and separate out the mundane operations into a local procedure, so that the actual list manipulation stands alone, and also because I have no idea what that piece of code is doing. Many variables should be moved into the local, and the item to manipulate should be passed into it, but that is another matter. Now go to the end ....
Procedure Advance(VAR Root : PRec; {rx, ry, rz: medcard; next: PRec} VAR Latt : PPLary; (3D lattice in schema format} VAR here, count : medCard); {Local to NumLatt.
- IdentIFy adjacent, accessible sites.
- if sites are unoccupied, insert them into LNext.
- Delete Self from Root.
- Set Root = Lnext.}
VAR LNext, PSelf : PRec; lx, ly, lz, {neighboring locations} dir : medCard; {directions} Conduct : boolean; {=accessible site}
(* 2--------------------2 *)
PROCEDURE operate;
BEGIN (* operate *) WITH PSelf^ DO FOR dir := 1 to 6 DO BEGIN {check all 6 directions} lX := rX; lY := rY; lZ := rZ; CASE dir of 1 : IF (rX > 1) THEN BEGIN {-X direction} lX := rX-1; Conduct := ((Latt^[rX]^[rY,rZ] AND Xn) = Xn); END ELSE Conduct := False; 2 : BEGIN {-Y direction} IF (rY = 1) THEN lY := ny ELSE lY := rY-1; Conduct := ((Latt^[rX]^[rY,rZ] AND Yn) = Yn); END; 3 : BEGIN {-Z direction} IF (rZ = 1) THEN lZ := nz ELSE lZ := rZ-1; Conduct := ((Latt^[rX]^[rY,rZ] AND Zn) = Zn); END; 4 : BEGIN {+Z direction} IF (rZ = nz) THEN lZ := 1 ELSE lZ := rZ+1; Conduct := ((Latt^[rX]^[rY,rZ] AND Zp) = Zp); END; 5 : BEGIN {+Y direction} IF (rY = ny) THEN lY := 1 ELSE lY := rY+1; Conduct := ((Latt^[rX]^[rY,rZ] AND Yp) = Yp); END; 6 : IF (rX >= nx) THEN Conduct := False ELSE BEGIN {+X direction} lX := rX+1; Conduct := ((Latt^[rX]^[rY,rZ] AND Xp) = Xp); END; END; {CASE} IF (Conduct AND (Latt^[lX]^[lY,lZ] < Occ)) THEN BEGIN {unoccupied site} {count newly accessible} inc(count); {insert into LNext} LInsert(LNext, lX, lY, lZ); {mark as occupied} Latt^[lX]^[lY,lZ] := Latt^[lX]^[lY,lZ] OR Occ; {check FOR breakthrough} IF ( (not Infinite) AND (lX = nx) AND ((Latt^[lX]^[lY,lZ] AND Xp) = Xp) ) THEN BEGIN Infinite := True; MinPath := here; END; END; {IF Conduct} END; {FOR dir} (* with *) END; (* operate *)
(* 2--------------------2 *)
BEGIN (* advance *) LNext := Nil; WHILE (Root <> Nil) DO BEGIN PSelf := Root; operate; Root := Root^.next; {advance through list} write('a'); dispose(PSelf); { <<=== program crashes here } write('b. '); END; (* while *) Root := LNext; END; {Advance}
The above makes it pretty obvious that the problem is NOT in the operate action, but in the list itself. The fact that dispose crashes shows that PSelf is not a valid pointer to a record, which includes *the fact that the record was created with new*
I think you should look into the areas where the list is created. You may have a global instance of an element, for example, that you are incorporating into the list somehow.
GPC new/dispose is dependant on the C malloc, I believe. If you are using DJGPP you can probably use my nmalloc, available on my site, which provides some hooks for examining the allocation chains and also detects most illegal frees. If it is linked ahead of the runtime library it will replace the library malloc stuff. But that should be only a last resort.