Accessing unloaded pointers

Post Reply
User avatar
DGDanforth
Posts: 1061
Joined: Tue Sep 17, 2013 1:16 am
Location: Palo Alto, California, USA
Contact:

Accessing unloaded pointers

Post by DGDanforth »

Hello, Chris!

> It is the latest version of Oberon that I am particularly interested in as I unable to think of a way to break it using normal programming practices.
> It may well be possible in BlackBox/Component Pascal but as I said, if that is so, the best way to avoid those problems is not to use Procedure variables in BlackBox/Component Pascal. There are better ways of doing the same thing in that language.

The code I'm about to present below doesn't use any procedure variables, only extensible objects, which is the normal use case these days.
I don't have access to the "latest" Oberon, whatever that may be these days, so I'm using BlackBox v1.7 recently released by the community.
It is up to you to judge whether the same problem can be reproduced in your environment of choice, but my guess is that if it supports module unloading, then it probably can be.

The sample code below involves four modules, which may seem like a lot, but conceptually the roles of each are clear:
SampleObjectDefinition - exports an abstract RECORD type;
SampleObjectImplementation - exports a concrete implementation of that type, including a type-bound procedure;
SampleObjectUser - retains an instance of the implementation object, which it holds on to using the abstract type. This module can call the implemented method via the abstract declaration;
SampleConfigurer - gives a concrete object instance for the SampleObjectUser to hold.

MODULE SampleObjectDefinition;

TYPE
AbstractType* = POINTER TO ABSTRACT RECORD END;

PROCEDURE (self: AbstractType) DoSomething*, NEW, ABSTRACT;

END SampleObjectDefinition.



MODULE SampleObjectImplementation;

IMPORT
SampleObjectDefinition;

TYPE
ConcreteType* = POINTER TO RECORD (SampleObjectDefinition.AbstractType) END;

PROCEDURE (self: ConcreteType) DoSomething*;
BEGIN
END DoSomething;

END SampleObjectImplementation.



MODULE SampleObjectUser;

IMPORT
SampleObjectDefinition; (* This module we can't unload, but SampleObjectImplementation can be unloaded. *)

VAR
sampleObject: SampleObjectDefinition.AbstractType;

PROCEDURE AssignObjectInstance* (object: SampleObjectDefinition.AbstractType);
BEGIN
sampleObject := object (* Store object instance without IMPORTing the implementation module. *)
END AssignObjectInstance;

PROCEDURE MakeObjectDoSomething*;
BEGIN
sampleObject.DoSomething (* Use the stored instance, calling the code that could be unloaded. *)
END MakeObjectDoSomething;

END SampleObjectUser.



MODULE SampleConfigurer;

IMPORT
SampleObjectImplementation, SampleObjectUser;

PROCEDURE Setup*;
VAR
instance: SampleObjectImplementation.ConcreteType;
BEGIN
NEW(instance);
SampleObjectUser.AssignObjectInstance(instance)
END Setup;

END SampleConfigurer.

^Q SampleConfigurer.Setup
^Q DevDebug.UnloadThis SampleConfigurer SampleObjectImplementation
^Q SampleObjectUser.MakeObjectDoSomething (* TRAP: illegal execution *)


Only the SampleConfigurer IMPORTs SampleObjectImplementation, so after the Setup both of these modules can be unloaded. After unloading the implementation, any attempt by the SampleObjectUser to call the methods of the object it holds results in a run-time error (trap).

> However, I wouldn't be surprised if somebody (like yourself :) ) could concoct an extreme pathological example to make it happen. I'm more interested in the sort of accidental usage that an average programmer might trip over.

This sort of failures due to module unloading happen all the time when I develop a visual element in BlackBox: whenever I reload its module after an edit, all the instances currently on screen fail to render and/or start throwing traps, because the framework keeps calling their - now unloaded - methods.

---=====---
Александр


--
Oberon@lists.inf.ethz.ch mailing list for ETH Oberon and related systems
https://lists.inf.ethz.ch/mailman/listinfo/oberon
User avatar
Josef Templ
Posts: 2047
Joined: Tue Sep 17, 2013 6:50 am

Re: Accessing unloaded pointers

Post by Josef Templ »

Shouldn't such questions be discussed on the community forum?
User avatar
DGDanforth
Posts: 1061
Joined: Tue Sep 17, 2013 1:16 am
Location: Palo Alto, California, USA
Contact:

Re: Accessing unloaded pointers

Post by DGDanforth »

Josef Templ wrote:Shouldn't such questions be discussed on the community forum?
Perhaps but if it leads to a change in the BB Framework then the Center is responsible.
User avatar
Josef Templ
Posts: 2047
Joined: Tue Sep 17, 2013 6:50 am

Re: Accessing unloaded pointers

Post by Josef Templ »

Any discussion on the community forum may eventually lead to center actions
since some of us monitor the community forum anyway.

This particular posting is confusing to me.
It is not clear who sent what to whom and for what reason.
From what I think I have understood I would not expect any center actions
in this case.

- Josef
cfbsoftware
Posts: 204
Joined: Wed Sep 18, 2013 10:06 pm
Contact:

Re: Accessing unloaded pointers

Post by cfbsoftware »

It's been taken from the middle of a discussion that has been going on for the last couple of days on the ETH Oberon mailing list. The relevant part started about here:

http://lists.inf.ethz.ch/pipermail/ober ... 09860.html
User avatar
Josef Templ
Posts: 2047
Joined: Tue Sep 17, 2013 6:50 am

Re: Accessing unloaded pointers

Post by Josef Templ »

As far as I know and what I have observed ,
BlackBox is not releasing the memory of the module upon unloading it but only decommits it
(see Kernel.UnloadMod).
The memory is inaccessible from that time on but not reused for other modules.
Calling any procedure of an unloaded module, be it via procedure variable or type bound procedures,
will then lead to a trap.
This is is different from what somebody posted on the mailing list, where it was
expected that the resulting behavior is random.

One alternative, treating procedure variables as pointers to the module by the GC, is possible
(I have done this in my PHD thesis) but is more complicated and leads to nasty compatibility issues.
I would only consider it if there is no memory management unit available and even then I am not sure.

The other alternative, not allowing an unload of a referenced module, is too restrictive in practice.

- Josef
User avatar
DGDanforth
Posts: 1061
Joined: Tue Sep 17, 2013 1:16 am
Location: Palo Alto, California, USA
Contact:

Re: Accessing unloaded pointers

Post by DGDanforth »

From a practical point of view it is very annoying when a module is unloaded but the view(s) created by the module are still visible.
If those views are accessed or uncovered, traps are generated.
I try and have in my CLOSE section a close of the views that the module created BUT that
forces all views to be at module scope and not created locally within a procedure.
If one forgets to do that then traps result.
-Doug
Post Reply