euslisp / EusLisp

EusLisp is an integrated programming system for the research on intelligent robots based on Common Lisp and Object-Oriented programming. [Manual](http://euslisp.github.io/EusLisp/manual.html ) [マニュアル](http://euslisp.github.io/EusLisp/jmanual.html )
Other
57 stars 50 forks source link

Not unwinding catchframes properly after return-from in compiled code #494

Open Affonso-Gui opened 2 years ago

Affonso-Gui commented 2 years ago

Catch frames are not properly unwinded after a return-from statement if they are the first element in the local stack after compiled.

For example:

;; foo.l
(defun foo ()
  (catch :this
    (return-from foo 10)))

Compile with euscomp foo.l and then:

eus$ (load "foo.so")
eus$ (sys:list-all-catchers)
(:reploop-select 0 :eusexit)
eus$ (foo)
10
eus$ (sys:list-all-catchers)
;; Segmentation Fault.
;; in (system:list-all-catchers)
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=-1311861392 x=b1ce9440 addr=22

Looking at the compiled code, we see that we are trying to unwind until local+0. However, the catch frame is registered in local[0], so we should rewind for "local-1".

/*foo*/
static pointer fooF1foo(ctx,n,argv,env)
register context *ctx;
register int n; register pointer argv[]; pointer env;
{ register pointer *local=ctx->vsp, w, *fqv=qv;
  numunion nu;
    if (n!=0) maerror();
    {jmp_buf jb;
    w = fqv[0];
    ctx->vsp=local+0;
    mkcatchframe(ctx,w,(jmp_buf *)jb);
    if ((w=(pointer)eussetjmp(jb))!=0) { /*fsp=vsp;*/ goto fooCAT4;}
    w = makeint((eusinteger_t)10L);
    ctx->vsp=local+6;
    unwind(ctx,local+0);
    local[0]=w;
    goto fooBLK3;
    w = local[6];
fooCAT4:
    if (w==(pointer)(1)) w=makeint(0);
    restorecatch(ctx);};
    local[0]= w;
fooBLK3:
    ctx->vsp=local; return(local[0]);}
Affonso-Gui commented 2 years ago

Similar results with:

(defun foo ()
  (catch :ok
    (block :this
      (catch :that
        (return-from :this 10)))))

Seems that the unwind call is always offset by 1?