Pieter.Muller@f11.n492.z5.fidonet.org (Pieter Muller) (12/06/90)
I found a nice way to track down those hard to find memory allocation errors.
The type where you allocate n bytes and use n+m bytes, usually clobbering
something else. Normally the program works until much later when the
clobbered data causes it to crash. I'm sure you know the type... :-)
Anyway, here is a debugging tool. It checks the heap consistency before and
after every procedure. Remember to compile all the suspect modules with the
(*$Q+*) switch to include procedure-tracing code. The heap consistency check
will catch the error because the heap linked list is interleaved with the
allocated memory.
(code fragment follows)
VAR DebugWindow :Window.WinType;
PROCEDURE TraceEntryProc();
VAR Used :WinType;
BEGIN
Used := Window.Used();
Window.Use(DebugWindow);
IO.WrStr("In: "); IO.WrStr(ProcTrace.Get_Name()); IO.WrLn;
IF NOT CheckHeap() THEN
IO.WrStr(" !Heap inconsistent (in)"); IO.WrLn;
IF KeyInAtomic() = ESC THEN HALT END;
END;
Window.Use(Used);
END TraceEntryProc;
PROCEDURE TraceExitProc();
VAR Used :WinType;
BEGIN
Used := Window.Used();
Window.Use(DebugWindow);
IO.WrStr("Out: "); IO.WrStr(ProcTrace.Get_Name()); IO.WrLn;
IF NOT CheckHeap() THEN
IO.WrStr(" !Heap inconsistent (out)"); IO.WrLn;
IF KeyInAtomic() = ESC THEN HALT END;
END;
Window.Use(Used);
END TraceExitProc;
PROCEDURE InitWinKernel();
VAR Used :WinType;
BEGIN
InitKeyboard();
InitKeys();
InitProcesses();
IF Indaba.DebugTrace THEN
Used := Window.Used();
DebugWindow := Window.Open(Window.WinDef(40,1,79,24,
Window.White, Window.Black,
TRUE, TRUE, FALSE, TRUE, Window.SingleFrame,
Window.Yellow, Window.Black));
Window.SetTitle(DebugWindow, " Debug Trace ", Window.RightUpperTitle);
ProcTrace.Install();
ProcTrace.Entry := TraceEntryProc;
ProcTrace.Exit := TraceExitProc;
Window.Use(Used);
END;
END InitWinKernel;
(*
* Check if the heap is consistent (Debug)
* JPI Modula-2 specific
*)
PROCEDURE CheckHeap() :BOOLEAN;
VAR
p :Storage.HeapRecPtr;
c :CARDINAL;
BEGIN
p := Storage.MainHeap^.next;
FOR c := 1 TO 50000 DO
IF p = NIL THEN RETURN FALSE END; (* should be endless ring *)
IF p = Storage.MainHeap THEN RETURN FALSE END; (* no endmarker *)
IF p^.size = 0FFFFH THEN RETURN TRUE END; (* Found endmarker *)
p := p^.next;
END;
RETURN FALSE; (* endless junk *)
END CheckHeap;
That's it.
Oh yes, a warning. I use JPI 1.17 and this code might not work as expected on
any other compiler.
-- Pieter
--
uucp: uunet!m2xenix!puddle!5!492!11!Pieter.Muller
Internet: Pieter.Muller@f11.n492.z5.fidonet.org