[M3devel] RuntimeError doesn't work quite as advertised

Tony Hosking hosking at cs.purdue.edu
Tue Apr 28 03:48:34 CEST 2009


On 28 Apr 2009, at 11:18, Mika Nystrom wrote:

> 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...

I'm not sure we can statically determine how a frame will be used.   
Can someone (Jay?) confirm whether signal handling on platforms  
without a stack walker are actually already using siglongjmp?  I have  
a feeling this may already be the case.

> 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




More information about the M3devel mailing list