[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