Aw: Re: problem with example 'dlg02'

Anton Vidovic anton.vidovic at gmx.de
Sun Jan 29 21:54:52 UTC 2023


Hello cage,

> After some more investigation with  a friend, the offending form seems
> could be reduced to:
> 
> -----
> (cffi:mem-aref de.anvi.croatoan::acs-map-array 'ncurses:chtype 108) ; → 0
> ----

I also tried to narrow down the source of the error, basically getting to the same conclusion, that it is a low-level cffi problem in accessing the alternate character set ACS used to draw the borders.

I also tried running the same code on older sbcl version, older linux machines, older library versions. Even though I still have older binaries which I built as late as end of november, which run as expected and where the error doesnt occur, now suddenly it happens on every single backup I had. I guess _something_ changed in the underlying C libraries, which are updated all the time, and code that worked for years now doesn't, a pretty scary thought.

But after a helpful discussion in #sbcl, the cause and thankfully a solution was quickly found.

For the sake of completeness, this is a minimal ncurses example, based on your test-menu, which triggers the bug without any of the library overhead except cffi:

(defsystem :test-menu
  :pathname "src"
  :serial t
  :depends-on (:cffi)
  :entry-point "test-menu::main"
  :build-operation program-op
  :components ((:file "main")))

(defpackage :test-menu
  (:use :cl
   :cffi))

(in-package :test-menu)

(cffi:defctype chtype :uint32)
(cffi:defctype window :pointer)

(cffi:defcfun ("initscr" initscr) window)
(cffi:defcfun ("addch" addch) :int (ch chtype))
(cffi:defcfun ("refresh" refresh) :int)
(cffi:defcfun ("getch" getch) :int)
(cffi:defcfun ("endwin" endwin) :int)

(cffi:define-foreign-library libncursesw
    (:unix
     (:or "libncursesw.so.6.3"))
    (t (:default "libncursesw")))

(cffi:use-foreign-library libncursesw)

(defparameter acs-map-array (cffi:foreign-symbol-pointer "acs_map"))

(defun main ()
  (initscr)
  (addch (cffi:mem-aref acs-map-array
                        :uint32
                        (char-code #\l)))
  (refresh)
  (getch)
  (endwin))

It should display one single ACS char and basically signals the same error.

The underlying cause of the error is the fact that acs-map-array, which is a pointer to the acs_map array, is basically allocated during build time, which obviously is wrong, and the fact that it worked till now just luck.

As soon as the function is called at run time, as in

(defun main ()
  (initscr)
  (addch (cffi:mem-aref (cffi:foreign-symbol-pointer "acs_map")
                        :uint32
                        (char-code #\l)))
  (refresh)
  (getch)
  (endwin))

the error doesnt occur any more. So the fix for the whole library is just that one line in the acs function, which is the only place the acs_map C array is accessed. I'm going to push that change in a minute, when you find time, please test and confirm that it also works for you.

There is also the question whether cffi:use-foreign-library should be called during build time or run time, but as long as it does not cause problems, I would let it stay as it is now, at build time.

Thanks for the report and the test case, it greatly accelerated the search.
A.



More information about the croatoan-devel mailing list