[e-lang] E-on-CL's principles of exception handling

Kevin Reid kpreid at attglobal.net
Thu Feb 23 12:33:49 EST 2006


The problem (as I see it) with E's (and Java's, Common Lisp's,  
Python's, etc. but they aren't trying to be capability languages)  
current exception semantics is that it constitutes a value-flow (I  
would say 'data-flow' if that didn't have an implication of just  
bits) path which is outside of capability semantics, in the *obvious*  
mapping to language structure.

For clarity, I shall now refer to 'throw' and 'catch', rather than  
'exceptions', as 'exception' is commonly used to refer to the  
description objects (e.g. 'FileNotFoundException') which are not  
particularly important.

That is, if we were to write an evaluator (whether interpreter or  
compiler) for E-as-it-is-now in an object-cap language which does not  
have 'throw', we would need to *add* the implicit exit path.

# examples in E syntax

If we ignore other forms of nonlocal exit,

   to foo(bar) {
     return [baz(bar)]
   }

would compile to something like:

   to foo(bar) {
     switch (baz.run(bar)) {
       match [==VALUE, v] {
         return [VALUE, __makeList.run(v)]
       }
       match [==EXCEPTION, e] {
        return [EXCEPTION, e]
       }
     }
   }


If we consider a language which has ejectors and not exceptions, then  
the path embedded in code disappears; but the 'throw' and 'catch'  
operations must be implemented using a global stack:

   try { foo } catch e { bar }

compiles to

   def previous__1 := __catcher
   try {
     escape ej__2 {
       __catcher := ej__2
       foo
     } catch candidate__3 {
       if (candidate__3 =~ e) {
         bar
       } else {
         previous__1.run(candidate__3)
       }
     }
   } finally {
     __catcher := previous__1
   }

and 'throw' is like

   def throw(e) {
     __catcher.run(e)
     EXIT("can't happen")
   }

This clearly (I hope) shows that there is an implicit information  
leak (whether or not we restrict exceptions to being Just Data). In  
the first case, the compilation shows an explicit path; in the  
second, every occurrence of 'catch' or 'throw' carries authority  
which would not pass any audit for DeepFrozen, Selfless, etc. in the  
'host' language.


The approach taken by E-on-CL to fix this is not to eliminate these  
paths, but to restrict their information (or permission) content.

Practically, programs must have ways to signal expected and  
unexpected kinds of failures:

Unexpected failures (e.g. "no such method") are indicated by 'throw',  
which is essentially unchanged, except that the exception is  
(effectively) placed in a special sealed box. The unsealer for these  
boxes is reserved for debugging/tracing tools and top-level error  
handling. Thus, ordinary code can determine that something it invoked  
within a particular 'try' block failed and no other details, but it  
can pass on the sealed exception to say "this is why I failed".

Expected failures in synchronous operation, those which the signaling  
code expects another part of the program to handle, are indicated by  
invoking ejectors. Since ejectors must be passed explicitly, this  
allows communication via nonlocal exit only where the parties have  
already communicated.


Expected failures in eventual operation will be handled by a not-yet- 
implemented mechanism where an object presenting the same interface  
as an ejector does a special 'throw' which uses a different sealer.

So that they may be passed across the network and used synchronously,  
these sealer/unsealer sets perform cryptographic (public key)  
encryption (if necessary; within a vat they are simple auditing-based  
sealers). The 'client' on one vat creates a pair and supplies the  
sealer to the 'server'; the 'server' uses the sealer to throw an  
exception which only the 'client' may decrypt.

These cryptographic sealers have a minor magic feature; like  
SturdyRefs, they are PassByCopy but do not reveal their bits (given a  
cooperating vat). This is necessary to allow the pairs to be created  
by unprivileged code without breaking determinism.

This mechanism is what I have worked out to handle secure exceptions  
in eventual programming. It seems to be almost equivalent to the use  
of ejectors in synchronous programming; it may be worth seeing if  
these systems can be unified, but I have not thought much about doing  
so yet.

-- 
Kevin Reid                            <http://homepage.mac.com/kpreid/>




More information about the e-lang mailing list