[M3devel] RuntimeError doesn't work quite as advertised

Tony Hosking hosking at cs.purdue.edu
Tue Apr 28 04:23:57 CEST 2009


On 28 Apr 2009, at 11:50, Jay wrote:

> 1) Should we just always use sigsetjmp/siglongjmp?
> Or, getting the signal mask is much extra expense usually unnecesary?
>   (imagine the case of there being a stack walker, where not even  
> setjmp is paid for)
> Folks aren't supposed to muck with it willy nilly and should expect  
> raising/catching an exception to restore to that which it was at the  
> point of the try?

I would have thought so, yes.  I thought I had seen use of setjmp/ 
longjmp instead of _setjmp/_longjmp but it appears some platforms  
don't restore signal masks (viz. I386_DARWIN).

> 2) The inlined NULL checks arounds the "barrier" calls:
>   - Aren't they just bloating the code for the unusual case?
>   - Aren't they better left in the barrier functions themselves?
>   - Besides leading to smaller and therefore faster code (except in  
> the usual
>   case of there being a NULL pointer deref, which is always going to  
> be slow anyway),
>   can't this then double or mostly double for a place to fix this?
>   That is, IF, but I doubt this is true, IF every pointer deref goes  
> through a "barrier"
>   function, the exceptions could be raised from them, right

The point is that we want to do a fast inline check via non-NIL  
references, so we need to explicitly check for those.  This is not the  
standard NIL check, since it is legal to load NIL from the heap.   
There are no exceptions to be raised here.  The explicit check for  
loading NIL is only for loads from the heap.  Not for stores to the  
heap.

> ?
>
>
>  Are the barrier calls placed adequately maybe?????
>  I don't think they are placed for untraced derefs (a fix Tony  
> recently put in)
>  and I imagine you might want those to act the same as traced null  
> derefs.
>  Maybe a pragma???
>
>
>  - Jay
>
>
> > To: hosking at cs.purdue.edu
> > Date: Mon, 27 Apr 2009 18:18:10 -0700
> > From: mika at async.caltech.edu
> > CC: m3devel at elegosoft.com
> > Subject: Re: [M3devel] RuntimeError doesn't work quite as advertised
> >
> > I think it ought to be safe to use siglongjmp.
> >
> > So we could attach a sigjmpbuf to whatever structure PushEFrame
> > builds only when it's doing it for a "RuntimeError", and on a  
> runtime
> > error that's not handled otherwise, we catch the unix signal and
> > call siglongjmp to get back to the exception handler...
> >
> > Here's an example in C:
> >
> > #include <setjmp.h>
> > #include <signal.h>
> >
> > sigjmp_buf env;
> >
> > void handler(int x) { siglongjmp(env,1); }
> >
> > main()
> > {
> > signal(SIGSEGV, handler);
> >
> > if(sigsetjmp(env,1)) {
> > printf("caught signal\n");
> > exit(0);
> > } else {
> > printf("initialized env\n");
> > }
> >
> > {
> > int *a=(void *)0;
> > printf("a is %d\n", *a /* SEGV */);
> > /* not reached */
> > }
> > }
> >
> > Mika
> >
> >
> > Tony Hosking writes:
> > >It's probably not generally safe to use RAISE inside a signal
> > >handler. There are esoteric rules as to what signal handlers can
> > >handle...
> > >
> > >I think we need to think harder on how best to reflect NIL  
> dereference
> > >as a signal. Perhaps we need explicit NIL checks after all...
> > >
> > >On 27 Apr 2009, at 18:31, Mika Nystrom wrote:
> > >
> > >> Ok so I tried the "obvious thing", namely, I changed  
> RTSignal.SegV to
> > >> do
> > >>
> > >> RAISE RuntimeError.E(RuntimeError.T.BadMemoryReference);
> > >>
> > >> Somewhat to my surprise, this does the right thing for a null  
> method.
> > >> But somewhat less surprisingly, it loops for NilJump and  
> NilDeref.
> > >> Is the machine jumping back and re-executing the same  
> instructions
> > >> after the signal handler returns?
> > >>
> > >> Would all hell break loose if one were to special-case EXCEPT
> > >> RuntimeError.E to store a thread-local jmp_buf that one does a
> > >> C-style longjmp to? (With a chain back to any higher  
> RuntimeError.E
> > >> handlers, I suppose...) Or is there a way to get the exception to
> > >> work out of the signal handler with the normal exception  
> mechanism?
> > >>
> > >> Mika
> > >
> > >> Mika Nystrom writes:
> > >>>
> > >>> Maybe someone else knows more about this than me...
> > >>>
> > >>> The following program:
> > >>>
> > >>> MODULE Main;
> > >>> IMPORT RuntimeError, IO;
> > >>>
> > >>> PROCEDURE Range() = BEGIN EVAL VAL(-1,CARDINAL) END Range;
> > >>>
> > >>> PROCEDURE Assert() = BEGIN <*ASSERT FALSE*> END Assert;
> > >>>
> > >>> PROCEDURE NilJump() = VAR x : PROCEDURE() := NIL; BEGIN x() END
> > >>> NilJump;
> > >>>
> > >>> PROCEDURE NilDeref() =
> > >>> VAR x : REF INTEGER := NIL; b : INTEGER;
> > >>> BEGIN b := x^ END NilDeref;
> > >>>
> > >>> PROCEDURE NilMethod() =
> > >>> TYPE T = OBJECT METHODS m() END;
> > >>> VAR t : T; BEGIN t.m() END NilMethod;
> > >>>
> > >>> BEGIN
> > >>> WITH ps = ARRAY OF PROCEDURE() { Range, Assert, NilMethod,  
> NilJump,
> > >>> NilDeref } DO
> > >>> FOR i := FIRST(ps) TO LAST(ps) DO
> > >>> TRY
> > >>> ps[i]()
> > >>> EXCEPT
> > >>> RuntimeError.E(e) => IO.Put("RuntimeError: " &
> > >>> RuntimeError.Tag(e) & " \n")
> > >>> END
> > >>> END
> > >>> END
> > >>> END Main.
> > >>>
> > >>> yields the following result:
> > >>>
> > >>> (1053)trs80:~/test/src>../FreeBSD4/prog
> > >>> RuntimeError: An enumeration or subrange value was out of range.
> > >>> RuntimeError: <*ASSERT*> failed.
> > >>>
> > >>>
> > >>> ***
> > >>> *** runtime error:
> > >>> *** Segmentation violation - possible attempt to dereference NIL
> > >>> *** pc = 0x8048a71 = NilMethod + 0x10 in ../src/Main.m3
> > >>> ***
> > >>>
> > >>> Abort
> > >>>
> > >>> Seems to me I ought to see a few more exceptions and not a  
> crash.
> > >>>
> > >>> I'm happy to investigate a bit more, but does anyone have a clue
> > >>> where
> > >>> to begin?
> > >>>
> > >>> Mika

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://m3lists.elegosoft.com/pipermail/m3devel/attachments/20090428/7a03d88a/attachment-0002.html>


More information about the M3devel mailing list