Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation fault occurs in funcall-ing a lambda-closure, when a function sets itself as the lambda-closure inside #463

Open
knorth55 opened this issue Sep 2, 2021 · 7 comments

Comments

@knorth55
Copy link
Contributor

knorth55 commented Sep 2, 2021

when a function (spam1) sets itself as a lambda-closure inside (setq *spam-func* #'spam1),
segmentation fault occurs in funcall (funcall *spam-func* (list 1))

test code: https://gist.github.com/knorth55/5f0e02f8c0103323d51d04aea482f57a#file-spam-l

Funcall case

#'spam : segmentation fault

(defun spam1 (x)
  (setq *spam-func* #'spam1)
  (format t "spam1: ~A ~%" x)
  (unix::sleep 1))


;; segmentation fault
(spam1 0)
(print *spam-func*)
(funcall *spam-func* 1)
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam1: 0 
(lambda-closure spam1 15975616 0 (x) (setq *spam-func* #'spam1) (format t "spam1: ~A ~%" x) (unix:sleep 1))
;; Segmentation Fault.
;; in (setq *spam-func* #'spam1)
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=-916475408 x=c95fb0c0 addr=4
Fatal: 

#'(lambda (x) (spam x)): OK

When we use (setq *spam-func* #'(lambda (x) (spam2 x))), we can avoid the segmentation fault.

(defun spam2 (x)
  (setq *spam-func* #'(lambda (xx) (spam2 xx)))
  (format t "spam2: ~A ~%" x)
  (unix::sleep 1))


;; OK
(spam2 0)
(print *spam-func*)
(funcall *spam-func* 1)
$ roseus spam.l 
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; intersection ;; geoclasses ;; geopack ;; geobody ;; primt ;; compose ;; polygon ;; viewing ;; viewport ;; viewsurface ;; hid ;; shadow ;; bodyrel ;; dda ;; helpsub ;; eushelp ;; xforeign ;; Xdecl ;; Xgraphics ;; Xcolor ;; Xeus ;; Xevent ;; Xpanel ;; Xitem ;; Xtext ;; Xmenu ;; Xscroll ;; Xcanvas ;; Xtop ;; Xapplwin 
connected to Xserver DISPLAY=:0
X events are being asynchronously monitored.
;; pixword ;; RGBHLS ;; convolve ;; piximage ;; pbmfile ;; image_correlation ;; oglforeign ;; gldecl ;; glconst ;; glforeign ;; gluconst ;; gluforeign ;; glxconst ;; glxforeign ;; eglforeign ;; eglfunc ;; glutil ;; gltexture ;; glprim ;; gleus ;; glview ;; toiv-undefined ;; fstringdouble irtmath irtutil irtc irtgeoc irtgraph ___time ___pgsql irtgeo euspqp pqp irtscene irtmodel irtdyna irtrobot irtsensor irtbvh irtcollada irtstl irtwrl irtpointcloud eusbullet bullet irtcollision irtx eusjpeg euspng png irtimage irtglrgb 
;; extending gcstack 0x61ae650[16374] --> 0x6638e90[32748] top=3c53
irtgl irtglc irtviewer 
EusLisp 9.27(b5be4c1 80d69c9) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
roseus ;; loading roseus("1.7.4-97-gb214284") on euslisp((9.27 ecublens Fri Nov 6 17:37:52 JST 2020 b5be4c1 80d69c9))
eustf roseus_c_util spam2: 0 
(lambda-closure nil 35317752 0 (x) (spam2 x))
spam2: 1 

Apply

#'spam : segmentation fault

(defun spam1 (x)
  (setq *spam-func* #'spam1)
  (format t "spam1: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam1 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam1: 0 
(lambda-closure spam1 32879808 0 (x) (setq *spam-func* #'spam1) (format t "spam1: ~A ~%" x) (unix:sleep 1))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=372082800 x=162d8740 addr=1f5b4c0
Fatal: 

#'(lambda (x) (spam x)) : segmentation fault

(defun spam2 (x)
  (setq *spam-func* #'(lambda (xx) (spam2 xx)))
  (format t "spam2: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam2 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam2: 0 
(lambda-closure nil 9147584 0 (xx) (spam2 xx))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=-584781136 x=dd24f180 addr=8b94c0
Fatal: 

#'spam-test: segmentation fault

(defun spam3-test (xx)
  (format t "spam3-test: ~A ~%" xx)
  (unix::sleep 1))

(defun spam3 (x)
  (setq *spam-func* #'spam3-test)
  (format t "spam3: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam3 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam3: 0 
(lambda-closure spam3-test 10745024 0 (xx) (format t "spam3-test: ~A ~%" xx) (unix:sleep 1))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=1339940976 x=4fdddf40 addr=a3f4c0
Fatal: 

#'(lambda (x) (spam-test x)): segmentation fault

(defun spam4-test (xx)
  (format t "spam3-test: ~A ~%" xx)
  (unix::sleep 1))

(defun spam4 (x)
  (setq *spam-func* #'(lambda (xx) (spam4-test xx)))
  (format t "spam4: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam4 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam4: 0 
(lambda-closure nil 17814720 0 (xx) (spam4-test xx))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=693430448 x=2954e780 addr=10fd4c0
Fatal: 

#'(lambda (xx) (format t "spam5-lambda: ~A ~%" xx) : segmentation fault

(defun spam5 (x)
  (setq *spam-func*
        #'(lambda (xx)
            (format t "spam5-lambda: ~A ~%" xx)))
  (format t "spam5: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam5 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam5: 0 
(lambda-closure nil 31184064 0 (xx) (format t "spam5-lambda: ~A ~%" xx))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=2103082992 x=7d5a7ec0 addr=1dbd4c0
Fatal: 

`(lambda-closure nil 0 0 (xx) (format t "spam6-lambda: ~A ~%" xx)) : OK

(defun spam6 (x)
  (setq *spam-func*
        `(lambda-closure nil 0 0 (xx)
                         (format t "spam6-lambda: ~A ~%" xx)))
  (format t "spam6: ~A ~%" x)
  (unix::sleep 1))

;; OK 
(spam6 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l 
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam6: 0 
(lambda-closure nil 0 0 (xx) (format t "spam6-lambda: ~A ~%" xx))
spam6-lambda: 1 
1.eus$ 
@knorth55
Copy link
Contributor Author

knorth55 commented Sep 2, 2021

I got this error when I try to add a new SMACH node in node callback function something like this.

(defun smach-callback (userdata)
  (send *sm* :add-node (instance state :init :name "new node" #'smach-callback)))

https://github.com/knorth55/rmui/blob/5040cd8a065903a2cadfefc92bc3b5093f5ac09e/rmuieus/euslisp/common/common-statenet-server.l#L48

@knorth55 knorth55 changed the title Segmentation fault occurs in funcall a lambda-closure when a function sets itself as the lambda-closure inside Segmentation fault occurs in funcall-ing a lambda-closure, when a function sets itself as the lambda-closure inside Sep 2, 2021
@knorth55
Copy link
Contributor Author

knorth55 commented Sep 2, 2021

I add test code and also tested with apply, but it is more complicated...
test code: https://gist.github.com/knorth55/5f0e02f8c0103323d51d04aea482f57a#file-spam-l

Apply

#'spam : segmentation fault

(defun spam1 (x)
  (setq *spam-func* #'spam1)
  (format t "spam1: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam1 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam1: 0 
(lambda-closure spam1 32879808 0 (x) (setq *spam-func* #'spam1) (format t "spam1: ~A ~%" x) (unix:sleep 1))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=372082800 x=162d8740 addr=1f5b4c0
Fatal: 

#'(lambda (x) (spam x)) : segmentation fault

(defun spam2 (x)
  (setq *spam-func* #'(lambda (xx) (spam2 xx)))
  (format t "spam2: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam2 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam2: 0 
(lambda-closure nil 9147584 0 (xx) (spam2 xx))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=-584781136 x=dd24f180 addr=8b94c0
Fatal: 

#'spam-test: segmentation fault

(defun spam3-test (xx)
  (format t "spam3-test: ~A ~%" xx)
  (unix::sleep 1))

(defun spam3 (x)
  (setq *spam-func* #'spam3-test)
  (format t "spam3: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam3 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam3: 0 
(lambda-closure spam3-test 10745024 0 (xx) (format t "spam3-test: ~A ~%" xx) (unix:sleep 1))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=1339940976 x=4fdddf40 addr=a3f4c0
Fatal: 

#'(lambda (x) (spam-test x)): segmentation fault

(defun spam4-test (xx)
  (format t "spam3-test: ~A ~%" xx)
  (unix::sleep 1))

(defun spam4 (x)
  (setq *spam-func* #'(lambda (xx) (spam4-test xx)))
  (format t "spam4: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam4 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam4: 0 
(lambda-closure nil 17814720 0 (xx) (spam4-test xx))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=693430448 x=2954e780 addr=10fd4c0
Fatal: 

#'(lambda (xx) (format t "spam5-lambda: ~A ~%" xx) : segmentation fault

(defun spam5 (x)
  (setq *spam-func*
        #'(lambda (xx)
            (format t "spam5-lambda: ~A ~%" xx)))
  (format t "spam5: ~A ~%" x)
  (unix::sleep 1))

;; segmentation fault
(spam5 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam5: 0 
(lambda-closure nil 31184064 0 (xx) (format t "spam5-lambda: ~A ~%" xx))
;; Segmentation Fault.
;; in (apply *spam-func* (list 1))
;; You are still in a signal handler.
;;Try reset or throw to upper level as soon as possible.
;; code=2103082992 x=7d5a7ec0 addr=1dbd4c0
Fatal: 

`(lambda-closure nil 0 0 (xx) (format t "spam6-lambda: ~A ~%" xx)) : OK

(defun spam6 (x)
  (setq *spam-func*
        `(lambda-closure nil 0 0 (xx)
                         (format t "spam6-lambda: ~A ~%" xx)))
  (format t "spam6: ~A ~%" x)
  (unix::sleep 1))

;; OK 
(spam6 0)
(print *spam-func*)
(apply *spam-func* (list 1))
$ eus spam.l 
configuring by "/home/shingo/install/jskeus/eus/lib/eusrt.l"
;; readmacro ;; object ;; packsym ;; common ;; constants ;; stream ;; string ;; loader ;; pprint ;; process ;; hashtab ;; array ;; mathtran ;; eusdebug ;; eusforeign ;; extnum ;; coordinates ;; tty ;; history ;; toplevel ;; trans ;; comp ;; builtins ;; par ;; helpsub ;; eushelp ;; fstringdouble 
EusLisp 9.27(b5be4c1) for Linux64 created on ecublens(Fri Nov 6 17:37:52 JST 2020)
spam6: 0 
(lambda-closure nil 0 0 (xx) (format t "spam6-lambda: ~A ~%" xx))
spam6-lambda: 1 
1.eus$ 

@knorth55
Copy link
Contributor Author

knorth55 commented Sep 2, 2021

I tried with the same functions with no arguments, and it works.
function argument seems similar to let (probably?), so I assume that closure does not work properly.

(defun noarg-spam1 ()
  (setq *spam-func* #'noarg-spam1)
  (format t "noarg-spam1: ~A ~%" nil)
  (unix::sleep 1))

(defun noarg-spam2 ()
  (setq *spam-func* #'(lambda () (noarg-spam2)))
  (format t "noarg-spam2: ~A ~%" nil)
  (unix::sleep 1))

(defun noarg-spam3-test (xx)
  (format t "noarg-spam3-test: ~A ~%" xx)
  (unix::sleep 1))

(defun noarg-spam3 ()
  (setq *spam-func* #'noarg-spam3-test)
  (format t "spam3: ~A ~%" nil)
  (unix::sleep 1))

(defun noarg-spam4-test (xx)
  (format t "noarg-spam4-test: ~A ~%" xx)
  (unix::sleep 1))

(defun noarg-spam4 ()
  (setq *spam-func* #'(lambda (xx) (noarg-spam4-test xx)))
  (format t "noarg-spam4: ~A ~%" nil)
  (unix::sleep 1))

(defun noarg-spam5 ()
  (setq *spam-func*
        #'(lambda (xx)
            (format t "noarg-spam5-lambda: ~A ~%" xx)))
  (format t "noarg-spam5: ~A ~%" nil)
  (unix::sleep 1))


(defun noarg-spam6 ()
  (setq *spam-func*
        `(lambda-closure nil 0 0 (xx)
                         (format t "noarg-spam6-lambda: ~A ~%" xx)))
  (format t "spam6: ~A ~%" nil)
  (unix::sleep 1))

;; OK 
(noarg-spam1)
(format t "*spam-func*: ~A~%" *spam-func*)
(funcall *spam-func*)

;; OK
(noarg-spam2)
(format t "*spam-func*: ~A~%" *spam-func*)
(funcall *spam-func*)

;; OK
(noarg-spam1)
(format t "*spam-func*: ~A~%" *spam-func*)
(apply *spam-func* nil)

;; OK
(noarg-spam2)
(format t "*spam-func*: ~A~%" *spam-func*)
(apply *spam-func* nil)

;; OK
(noarg-spam3)
(format t "*spam-func*: ~A~%" *spam-func*)
(apply *spam-func* (list 1))

;; OK
(noarg-spam4)
(format t "*spam-func*: ~A~%" *spam-func*)
(apply *spam-func* (list 1))

;; OK
(noarg-spam5)
(format t "*spam-func*: ~A~%" *spam-func*)
(apply *spam-func* (list 1))

;; OK
(noarg-spam6)
(format t "*spam-func*: ~A~%" *spam-func*)
(apply *spam-func* (list 1))

@Affonso-Gui
Copy link
Member

There are two conditions for lambda-closures to cause a segmentation fault in eus:

  1. The bind frame is non-global (non zero) (lambda-closure name bind-frame fbind-frame &rest body)
  2. The function body references a non-local variable.

The problem has nothing to do with funcall or apply or lambda, but is rather originated from trying to access the *spam-func* global variable from a non-zero bind frame.

(defun spam1 (x)
  (if (zerop x) (setq *spam-func* #'spam1))
  (format t "spam1: ~A ~%" x)
  (unix::sleep 1))


;; ok
(spam1 0)
(print *spam-func*)
(funcall *spam-func* 1)

;; segmentation fault
(funcall *spam-func* 0)

And yes, function arguments are similar to let and introduce new bind frames, so within functions with no arguments the bind frame is global (zero) and therefore segmentation faults does not occur.

(defun foo () #'foo)
(defun bar (b) #'bar)

(foo)
;; (lambda-closure foo 0 0 nil #'foo)
(bar 1)
;; (lambda-closure bar 94419140493560 0 (b) #'bar)

Segmentation also happens for fbind-frames similarly.

There is no proper solution for this problem yet, but some workarounds are:

  • avoid global variables in the body, when possible
  • force the bind-frame to zero (setf)
  • compile the code

@knorth55
Copy link
Contributor Author

knorth55 commented Sep 4, 2021

@Affonso-Gui thanks, it is quite unstable implementation of closure.
I'm not familiar with the closure,
but I think we can disable closure function because euslisp is object-oriented lisp.
Another solution is implement the closure properly, but it will take plenty of time.
(BTW, whole structure of euslisp should be closure-based language, and rewrite class as one implementation of closure, i thought)

(setq *a* 0)

(let ((a 0))
  (setq *spam0-func*
        #'(lambda ()
            (setq a (+ a 1))
            (print a))))

(let ((a 0))
  (setq *spam1-func*
        `(lambda-closure nil 0 0 ()
            (setq a (+ a 1))
            (print a))))

(let ((a 0))
  (setq *spam2-func*
        #'(lambda ()
            (setq *a* (+ *a* 1))
            (print *a*))))


; (print *spam0-func*)
; (funcall *spam0-func*)

; (print *spam1-func*)
; (funcall *spam1-func*)

; (print *spam2-func*)
; (funcall *spam2-func*)

@Affonso-Gui
Copy link
Member

The core of the problem itself is not that complicated. We either need to find a way to validate pointer addresses before usage or keep them while being referenced.

It is one project that has been in my list for quite some time but I was kind of reluctant to dig in the garbage collector. Maybe it's time to take a more serious try at the problem.

@Affonso-Gui
Copy link
Member

@knorth55

So I took the time and was able to develop a proof-of-concept implementation of closures using cons cells instead of the current struct bindframe Affonso-Gui@7e34755

eus$ (let ((a 0)) (setq fn #'(lambda () (incf a))))
;; (lambda-closure nil ((a . 0)) 0 nil (incf a))                                                     
eus$ (funcall fn)
;; 1                                                                                                 
eus$ (funcall fn)
;; 2                                                                                                 
eus$ (funcall fn)
;; 3                                                                                                 
eus$ (funcall fn)
;; 4                                                                                                 
eus$ (funcall fn)
;; 5                                                                                                 
eus$ fn
;; (lambda-closure nil ((a . 5)) 0 nil (incf a))    

We probably should use some other custom class to make things a little bit more hidden from the end user, and definitely do the same for the fletframe (and maybe the specialbindframe?), but as I said this is only of a proof-on-concept implementation.

The problem with the current method is that new frames are stacked on top of a vsp which is reset after each evaluation, making it impossible to keep track of bind frames simply by using their memory address.
The solution was to use proper lisp objects (in this case cons cells) rather than c structures + integer addresses. This way the objects are allocated more carefully and the gc can do its magic to keep referenced frames alive while getting rid of old ones.

The core implementation itself is rather simple, but as you can see in the diff it is kinda tricky because I had to replace all references and all NULLs to NILs.

CC. @708yamaguchi @pazeshun

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants