[comp.lang.modula2] Tracing Memory Allocation Errors

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