[Date Prev][Date Next][Thread Prev][Thread Next][Author Index][Date Index][Thread Index]

Re: SAFEty and the Cross Referencing of BLASTs

> From vlad!mark Sat Dec  1 20:47:34 1990

> [modified definition]:
> If a [member] function is declared SAFE, then it may not allocate any
> memory, it may not BLAST anything which it doesn't catch, and it may
> only call [member] function which are themselves declared SAFE. []

Why the restriction to member functions?  If a global function causes
a memory allocation or a BLAST, it's just as unsafe.

This implies a need to attach SAFE declarations to global functions,
and to check them.  Which means we have to be able to attach them to
most, but not all, of the system library includes, too.

> Unfortunately, it is sometimes possible to know when Bar::zip()
> specifically is being invoked, and therefore conceivably useful to
> know that this method specifically is SAFE even if the zip() message
> starting at Bar is not in general SAFE.  I have an idea how one would
> accomodate this case, but unless anyone feels it is likely to be
> needed I will keep this complex wrinkle to myself.

The English-language approach would be to use SAFE to mean local or
temporary safety and SECURE to mean global, worry-free (and possibly
intrusive) safety.  Thus SECURE could be used to impose the SAFE
contract on the descendants, while SAFE did not.

Unfortuntely, SECURE is not as strongly mnemonic for what we're doing,
and I expect we would want use SAFE to mean the inherited contract, and
add a less-than-SAFE keyword later if the non-inherited form is ever

(The term "entailment" comes to mind.  Not just for SAFE, but for all the
 other contracts imposed on the children's children's children, yea, even
 onto the n'th generation.)

> When allocating an object through a SAFE constructor, one can directly
> use "new" instead of relying on the various CONSTRUCT macros, as we
> know there is neither a garbage collection issue (SAFE routines cannot
> trigger collection activity) nor a finalization issue (as the
> constructor cannot BLAST).  In fact, XLint should warn exactly about
> uses of "new" in calling constructors not declared SAFE.

Nevertheless, now that we're using various CONSTRUCT macros, I'd prefer
to use them everywhere, perhaps with an additional flavor equivalent to a
bare 'new', rather than hopping back and forth between the normal language
construct and our extensions.

> Inside the Server, SAFE methods of Shepherds would not have to lock
> the server into memory, as nothing the method does may trigger an
> attempt to purge Shepherds from memory.  SAFE methods should also not
> fault (since faulting may allocate memory), so the SAFE declaration on
> Shepherd methods probably occurs below the patriarch in the class
> hierarchy (which is sufficient to suppress locking).  Hmm... I'm
> suddenly confused about this one (especially the interactions between
> SAFE and NO_FAULT).  Michael and Dean: any thoughts?  In any case, my
> confusion here should not affect what you need to do, Roland.

You'll need to ask Dean about locking.  Shepherds are simple:  At the
PATRIARCH level only NOFAULT methods can be SAFE, so SAFE is a stronger
qualification which must include NOFAULT.  (SAFE is also stronger because
NOFAULT methods can be overridden by faulting methods.)

I suspect that the already-defined NOFAULT methods of Abraham may end
up being the only SAFE methods that PATRIARCHs ever have.  What else
can you think of that a Shepherd might do with only the information
available in the stub?  (Only think I can think of is a SAFE analog
of isKindOf().  knownToBeKindOf()?)

Yes, you could have SAFE methods defined below the PATRIARCH.  But
(unless you've found another NOFAULT method) your class should then
be a COPY rather than a SHEPHERD_ANCESTOR, so no stubs can descend
from it.  (Also, it should be NOT_A_TYPE, as with everything else
below a PATRIARCH and isn't another PATRIARCH.)

> [] Since X4Ref has no way of knowing that there are not other
> subclasses of Foo lurking in other modules, it cannot really be
> confident that the above is all the BLASTs which the Foo::zip()
> message may cause.  Therefore, we introduce the new construct

> In order to prevent an unreasonable explosion of BLASTS_UNDER in the
> output, we need information about who may subclass a class.  If in
> analyzing a group we know we have seen all possible subclasses of Foo,
> then we can remove any BLASTS_UNDER(Foo::<anything>) that remain after
> the above trasitive propogation process.

When documenting a class in a library, you can never be sure that
you have found all the subclasses, because more can be defined at
a later time.  Therefore you can never remove the BLASTS_UNDER()

(Once LEAF is enforced, of course, BLASTS_UNDER() would not be
generated when a LEAF member function is called through a pointer
to its actual class.  On the other hand, that is a "should never
happen" in our abstract/implementation class style.)


Related thoughts:

Retaining the BLASTS_UNDER() term in the documentation gives a (nearly?)
(complete?) map of who calls what.  This may not be desirable, either
because it is a lot of information, or because it gives more information
out with the documentation than we really want to give.  Once we reach
the shippable documentation, most of the classes are unlikely to be
subclassed further.  While we are developing, generating a new list
is better than paying human attention to BLASTS_UNDER().

In a more formal development environment, there would be a specification
that would define the actual contract for the modules, and the
documentation would either BE the specification, or would be written from
it.  Does the appearance of a non-open-ended list of BLASTS in such a
document imply a "contract" not to add any more?  (How would you feel
if your new unix release added a bunch of previously undocumented ERRNO
values for returns from the standard system calls?)

I think our documentation should make it very clear that the BLAST
list is the output from a tool, and that future releases may change
the set that return from any given member function call.  Also, later
releases should have, as part of their documentation, a list of member
functions whose unhandled BLAST set has changed.  Otherwise, adding a
new BLAST becomes heavyweight for our developers, potentially blowing
away their already-working code.

Should the bomb package have a way to define BLASTs that are intended
as a non-catchable global error?  Is the ALL_BUT mechanism a bad one?