[M3devel] RuntimeError doesn't work quite as advertised

Mika Nystrom mika at async.caltech.edu
Tue Apr 28 03:18:10 CEST 2009


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



More information about the M3devel mailing list