[Oberon] When is it safe to unload a module?

Andreas Pirklbauer andreas_pirklbauer at yahoo.com
Mon Aug 6 05:01:42 CEST 2018


  > What would I have to do to make the system crash after this
  > sequence of calls to demonstrate the problem?

Easy: Just overwrite the module area previously occupied by M2:

Compile M4 (which happens to “fit” where M2 used to be) and M5
below (which will be loaded where M3 used to be located), restart
the system, and execute the following sequence:

   M3.Init             # load M0, M1, M2, M3
   M3.SetGProc1        # set M1.gproc to M2.P (global procedure variable reference)
   M1.P                # executes M1.P (which calls M1.grpoc, which is M2.P), OK
   System.Free M3 ~    # unload M3
   System.Free M2 ~    # unload M2
   M1.P                # still executes (since the module area of the old M2 has NOT been overwritten yet)
                           # this is already scary - the code is still there, but the module is unloaded
   M5.Init             # this overwrites the module area previously occupied by M3
   M4.Init             # this overwrites the module area previously occupied by M2
   System.ShowModules  # to verify that M4 is indeed where M2 was before
   M1.P                # TRAP (M1.gproc has not changed, but the contents
                              of the memory location it points TO has)
   
What you see here is this: M4 is now where M2 used to be in
memory. M4.P executes M4.gproc (which is NIL).

And this leads to a TRAP (doesn’t actually crash the system, but you
get the point: What if M1.P points to some random location in M4’).

PS: I would need to create a second set of modules that nicely shows
a crashing system in all possible cases (type tag ref. proc var ref)
AND which bear resemblance to "real world” cases (otherwise we'd
end up having an academic exercise here, which is not interesting)


-ap


-----------------------------------------------------------
MODULE M4;
  IMPORT M0;

  TYPE Ptr* = POINTER TO Rec;
    Rec* = RECORD (M0.Rec) END ;  (*extension of M0.Rec*)

  VAR gptr*: Ptr;  (*same variable size (8 bytes) as module M2*)
    gproc*: M0.Proc;

  PROCEDURE P*; BEGIN gproc END P;  (*therefore M4.P at same offset from "M.data" as M2.P*)

PROCEDURE Init*; BEGIN gproc := NIL END Init;
END M4.

------------------------------------------------------------------------
MODULE M5; (*identical to M2*)
  IMPORT M0;

  TYPE Ptr* = POINTER TO Rec;
    Rec* = RECORD (M0.Rec) END ;  (*extension of M0.Rec*)

  VAR gptr*: Ptr;
    gproc*: M0.Proc;

  PROCEDURE P*; BEGIN END P;

  PROCEDURE SetGPtr*(q: M0.Ptr); BEGIN gptr := q(Ptr) END SetGPtr;
  PROCEDURE SetLPtr*(q: M0.Ptr); BEGIN gptr.lptr := q(Ptr) END SetLPtr;

  PROCEDURE SetGProc*(q: M0.Proc); BEGIN gproc := q END SetGProc;
  PROCEDURE SetLProc*(q: M0.Proc); BEGIN gptr.lproc := q END SetLProc;

  PROCEDURE Init*; BEGIN NEW(gptr) END Init;

BEGIN Init
END M5.

------------------------------------------------------------------------






More information about the Oberon mailing list