[M3devel] RuntimeError doesn't work quite as advertised

Jay jay.krell at cornell.edu
Tue Apr 28 03:50:58 CEST 2009


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?

 

 

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?

 

 

 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/18378cfa/attachment-0002.html>


More information about the M3devel mailing list