lispnik / iup

Common Lisp CFFI bindings to the IUP Portable User Interface library (pre-ALPHA)
Other
139 stars 7 forks source link

A workflow that leads to a memory fault: re-defining a missing callback #31

Closed vindarel closed 5 years ago

vindarel commented 5 years ago

It's been twice or more that I get an unhandled memory fault with the following workflow.

I quickload iup, iup-scintilla, I define the dialogs function and I run it (with the sb-int division by zero trap on sbcl) . I select "message-dialog", which doesn't exist yet, so I get a nice error. Now I copy-paste it (style warning: handle is unused), I re-run (dialogs) but I get a memory error:

Unhandled memory fault at #x0.
   [Condition of type SB-SYS:MEMORY-FAULT-ERROR]

Restarts:
 0: [RETRY] Retry SLIME REPL evaluation request.
 1: [*ABORT] Return to SLIME's top level.
 2: [REMOVE-FD-HANDLER] Remove #<SB-IMPL::HANDLER INPUT on descriptor 4: #<CLOSURE (LABELS SWANK/SBCL::RUN :IN SWANK/BACKEND:ADD-FD-HANDLER) {1004BF542B}>>
 3: [ABORT] Exit debugger, returning to top level.

Backtrace:
  0: (SB-SYS:MEMORY-FAULT-ERROR #<unused argument> #.(SB-SYS:INT-SAP #X00000000))
  1: ("foreign function: call_into_lisp")
  2: ("foreign function: funcall2")
  3: ("foreign function: handle_trap")
  4: ("foreign function: #x41AFC0")
  5: (IUP:OPEN)
  6: (IUP::CALL-WITH-IUP #<FUNCTION (LAMBDA NIL :IN DIALOGS) {1001B881EB}>)
  7: ((LAMBDA ()))
  8: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SB-INT:WITH-FLOAT-TRAPS-MASKED (:DIVIDE-BY-ZERO :INVALID) (DIALOGS)) #<NULL-LEXENV>)
  9: (EVAL (SB-INT:WITH-FLOAT-TRAPS-MASKED (:DIVIDE-BY-ZERO :INVALID) (DIALOGS)))
 --more--

and I must restart SBCL. Doing it on the right order works fine.

SBCL 1.4.5 Debian.

lispnik commented 5 years ago

I think the message-dialog callback hadn't been defined yet, so when the button is pressed, lisp error and IUP never gets to handle the callback response. That is probably a bad thing for IUP. I looked at the callback handler code and saw that this case is not covered by the restarts.

I've fixed that in branch issue/31. On an error, a new restart case will be available: USE-DEFAULT, which basically simulates a callback returning IUP:+DEFAULT+. That should keep IUP happy and uncorrupted.

If you have time, would you kindly checkout the issue/31 branch and try the error-test.lisp example? It will demonstrate recovery from several kinds of errors including this one.

vindarel commented 5 years ago

I don't see a USE-DEFAULT restart, only

The function COMMON-LISP-USER::MESSAGE-DIALOG is undefined.
   [Condition of type UNDEFINED-FUNCTION]

Restarts:
 0: [CONTINUE] Retry calling MESSAGE-DIALOG.
 1: [USE-VALUE] Call specified function.
 2: [RETURN-VALUE] Return specified values.
 3: [RETURN-NOTHING] Return zero values.
 4: [USE-DEFAULT] Continue by returning IUP:+DEFAULT+
 5: [RETRY] Retry SLIME REPL evaluation request.
 --more--

Backtrace:
  0: (SB-VM::TAIL-CALL-SYMBOL #.(SB-SYS:INT-SAP #X00AB2BD0))
  1: (IUP::INVOKE-CALLBACK MESSAGE-DIALOG (#.(SB-SYS:INT-SAP #X00AB2BD0)) (#.(SB-SYS:INT-SAP #X00AB2BD0)))
  2: ((LAMBDA (SB-ALIEN::ARGS-POINTER SB-ALIEN::RESULT-POINTER FUNCTION) :IN "/home/vince/quicklisp/local-projects/iup/iup/iup.lisp") #<unavailable argument> #<unavailable argument> #<unavailable argument>..
  3: ("foreign function: funcall_alien_callback")
  4: ("foreign function: callback_wrapper_trampoline")
  5: ("foreign function: #x20100F32")
  6: (IUP::CALL-WITH-IUP #<FUNCTION (LAMBDA NIL :IN DIALOGS) {10031E066B}>)
  7: ((LAMBDA ()))
  8: (SB-INT:SIMPLE-EVAL-IN-LEXENV (SB-INT:WITH-FLOAT-TRAPS-MASKED (:DIVIDE-BY-ZERO :INVALID) (DIALOGS)) #<NULL-LEXENV>)
  9: (EVAL (SB-INT:WITH-FLOAT-TRAPS-MASKED (:DIVIDE-BY-ZERO :INVALID) (DIALOGS)))
 --more--

I pulled changes, quickloaded IUP (it seemed to rebuild stuff) and tried as before. Clicking on say "message dialog" which isn't defined yet gives me those restarts. Do I miss something ?

lispnik commented 5 years ago

Hi, the restart is there in your snippet:

 4: [USE-DEFAULT] Continue by returning IUP:+DEFAULT+

It will let you recover from this error without crashing IUP, e.g. from the errors-test.lisp example:

oopsies
vindarel commented 5 years ago

oh ok my bad!

Usability concern, then: I can't press q, this leads to the memory error. As a user, I'd like very much to use q as usual. (What is q bound to ?)

lispnik commented 5 years ago

Seems to be sly-db-quit in Sly at least. I'm not sure how make it work. Maybe put a key in sly-db-mode-map that invokes restart use-default by name.

vindarel commented 5 years ago

It's sldb-quit for Slime.

vindarel commented 5 years ago

No answers neither on reddit nor on SO: https://stackoverflow.com/questions/56346674/in-the-debugger-can-we-make-q-choose-a-given-restart (to make q call a given restart). It is probably not the right question/solution.

vindarel commented 5 years ago

A hint on SO: https://common-lisp.net/project/slime/doc/html/Other-configurables.html#g_t_002aSLDB_002dQUIT_002dRESTART_002a

SWANK:SLDB-QUIT-RESTART

This variable names the restart that is invoked when pressing q (see sldb-quit) in SLDB. For SLIME evaluation requests this is unconditionally bound to a restart that returns to a safe point. This variable is supposed to customize what q does if an application’s thread lands into the debugger (see SWANK:GLOBAL-DEBUGGER).

(setf swank:sldb-quit-restart 'sb-thread:terminate-thread)

but maybe our problem is fixed somewhat differently, with https://github.com/lispnik/iup/pull/40 maybe ?