Subject: bug#63881: 29.0.91; apropos-documentation fails when load-history contains element whose CAR is nil

From: Visuwesh <[email-masked]>
Date: Sun, 04 Jun 2023 08:37:08 +0530

As per (info "(elisp) Where Defined"), load-history may contain an
element whose CAR is nil if eval-buffer was used to evaluate a defun
in a non-file-visiting buffer.

After such an entry is added to load-history, apropos-documentation
fails with the backtrace at end.

To reproduce the issue,

    1. emacs -Q
    2. Insert (defun test () t)
    3. M-x eval-buffer RET
    4. Confirm that a nil entry is present in load-history by evaluating
       (alist-get nil load-history 'none)
    5. C-h d any RET

The problem lies in apropos--map-preloaded-atoms in the part

    (dolist (x load-history)
      (when (string-match preloaded-regexp (car x))
                                           ^^^^^^^^
        (dolist (def (cdr x))
          (cond
           ((symbolp def) (funcall f def))
           ((eq 'defun (car-safe def)) (funcall f (cdr def)))))))))

----

Debugger entered--Lisp error: (wrong-type-argument stringp nil)
  string-match("\\`/home/viz/lib/ports/emacs/lisp/\\(?:abbrev\\|b\\(?:..." nil)
  (if (string-match preloaded-regexp (car x)) (progn (let ((tail (cdr x))) (while tail (let ((def (car tail))) (cond ((symbolp def) (funcall f def)) ((eq ... ...) (funcall f ...))) (setq tail (cdr tail)))))))
  (let ((x (car tail))) (if (string-match preloaded-regexp (car x)) (progn (let ((tail (cdr x))) (while tail (let ((def ...)) (cond (... ...) (... ...)) (setq tail (cdr tail))))))) (setq tail (cdr tail)))
  (while tail (let ((x (car tail))) (if (string-match preloaded-regexp (car x)) (progn (let ((tail (cdr x))) (while tail (let (...) (cond ... ...) (setq tail ...)))))) (setq tail (cdr tail))))
  (let ((tail load-history)) (while tail (let ((x (car tail))) (if (string-match preloaded-regexp (car x)) (progn (let ((tail ...)) (while tail (let ... ... ...))))) (setq tail (cdr tail)))))
  (let ((preloaded-regexp (concat "\\`" (regexp-quote lisp-directory) (regexp-opt preloaded-file-list) "\\.elc?\\'"))) (let ((tail load-history)) (while tail (let ((x (car tail))) (if (string-match preloaded-regexp (car x)) (progn (let (...) (while tail ...)))) (setq tail (cdr tail))))))
  apropos--map-preloaded-atoms((closure ((sv) (sf) (v) (f)) (symbol) (progn (setq f (apropos-safe-documentation symbol)) (setq v (get symbol 'variable-documentation))) (if (integerp v) (setq v nil)) (progn (setq f (apropos-documentation-internal f)) (setq v (apropos-documentation-internal v))) (progn (setq sf (apropos-score-doc f)) (setq sv (apropos-score-doc v))) (if (or f v) (if (setq apropos-item (cdr (assq symbol apropos-accumulator))) (progn (if f (progn (setcar ... f) (setcar apropos-item ...))) (if v (progn (setcar ... v) (setcar apropos-item ...)))) (setq apropos-accumulator (cons (list symbol (+ ... sf sv) f v) apropos-accumulator))))))
  funcall(apropos--map-preloaded-atoms (closure ((sv) (sf) (v) (f)) (symbol) (progn (setq f (apropos-safe-documentation symbol)) (setq v (get symbol 'variable-documentation))) (if (integerp v) (setq v nil)) (progn (setq f (apropos-documentation-internal f)) (setq v (apropos-documentation-internal v))) (progn (setq sf (apropos-score-doc f)) (setq sv (apropos-score-doc v))) (if (or f v) (if (setq apropos-item (cdr (assq symbol apropos-accumulator))) (progn (if f (progn (setcar ... f) (setcar apropos-item ...))) (if v (progn (setcar ... v) (setcar apropos-item ...)))) (setq apropos-accumulator (cons (list symbol (+ ... sf sv) f v) apropos-accumulator))))))
  (let ((standard-input (current-buffer)) (apropos-sort-by-scores apropos-documentation-sort-by-scores) f v sf sv) (apropos-documentation-check-doc-file) (funcall (if do-all #'mapatoms #'apropos--map-preloaded-atoms) #'(lambda (symbol) (progn (setq f (apropos-safe-documentation symbol)) (setq v (get symbol 'variable-documentation))) (if (integerp v) (setq v nil)) (progn (setq f (apropos-documentation-internal f)) (setq v (apropos-documentation-internal v))) (progn (setq sf (apropos-score-doc f)) (setq sv (apropos-score-doc v))) (if (or f v) (if (setq apropos-item (cdr ...)) (progn (if f ...) (if v ...)) (setq apropos-accumulator (cons ... apropos-accumulator)))))) (apropos-print nil "\n----------------\n" nil t))
  (progn (let ((standard-input (current-buffer)) (apropos-sort-by-scores apropos-documentation-sort-by-scores) f v sf sv) (apropos-documentation-check-doc-file) (funcall (if do-all #'mapatoms #'apropos--map-preloaded-atoms) #'(lambda (symbol) (progn (setq f (apropos-safe-documentation symbol)) (setq v (get symbol ...))) (if (integerp v) (setq v nil)) (progn (setq f (apropos-documentation-internal f)) (setq v (apropos-documentation-internal v))) (progn (setq sf (apropos-score-doc f)) (setq sv (apropos-score-doc v))) (if (or f v) (if (setq apropos-item ...) (progn ... ...) (setq apropos-accumulator ...))))) (apropos-print nil "\n----------------\n" nil t)))
  (unwind-protect (progn (let ((standard-input (current-buffer)) (apropos-sort-by-scores apropos-documentation-sort-by-scores) f v sf sv) (apropos-documentation-check-doc-file) (funcall (if do-all #'mapatoms #'apropos--map-preloaded-atoms) #'(lambda (symbol) (progn (setq f ...) (setq v ...)) (if (integerp v) (setq v nil)) (progn (setq f ...) (setq v ...)) (progn (setq sf ...) (setq sv ...)) (if (or f v) (if ... ... ...)))) (apropos-print nil "\n----------------\n" nil t))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))
  (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (let ((standard-input (current-buffer)) (apropos-sort-by-scores apropos-documentation-sort-by-scores) f v sf sv) (apropos-documentation-check-doc-file) (funcall (if do-all #'mapatoms #'apropos--map-preloaded-atoms) #'(lambda (symbol) (progn ... ...) (if ... ...) (progn ... ...) (progn ... ...) (if ... ...))) (apropos-print nil "\n----------------\n" nil t))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer))))
  (let ((temp-buffer (generate-new-buffer " *temp*" t))) (save-current-buffer (set-buffer temp-buffer) (unwind-protect (progn (let ((standard-input (current-buffer)) (apropos-sort-by-scores apropos-documentation-sort-by-scores) f v sf sv) (apropos-documentation-check-doc-file) (funcall (if do-all #'mapatoms #'apropos--map-preloaded-atoms) #'(lambda ... ... ... ... ... ...)) (apropos-print nil "\n----------------\n" nil t))) (and (buffer-name temp-buffer) (kill-buffer temp-buffer)))))
  apropos-documentation(("pcomplete") nil)
  funcall-interactively(apropos-documentation ("pcomplete") nil)
  call-interactively(apropos-documentation nil nil)
  command-execute(apropos-documentation)

In GNU Emacs 29.0.91 (build 2, x86_64-pc-linux-gnu, X toolkit, Xaw
 scroll bars) of 2023-06-01 built on astatine
Repository revision: 17c7915ab947ebeec6ea5ad3eb4cad1f24d5d4fc
Repository branch: emacs-29
Windowing system distributor 'The X.Org Foundation', version 11.0.12101007
System Description: Debian GNU/Linux 12 (bookworm)

Configured using:
 'configure --with-sound=alsa --with-x-toolkit=lucid --with-json
 --without-xaw3d --without-gconf --without-libsystemd --without-cairo'
Configured features:
ACL DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG JSON
LIBOTF LIBSELINUX LIBXML2 MODULES NOTIFY INOTIFY PDUMPER PNG RSVG
SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS WEBP X11 XDBE XFT
XIM XINPUT2 XPM LUCID ZLIB
Important settings:
  value of $LC_MONETARY: ta_IN.UTF-8
  value of $LC_NUMERIC: ta_IN.UTF-8
  value of $LANG: en_GB.UTF-8
  locale-coding-system: utf-8-unix

Major mode: ELisp/l

Minor modes in effect:
  bug-reference-prog-mode: t
  csv-field-index-mode: t
  recentf-mode: t
  shell-dirtrack-mode: t
  server-mode: t
  paredit-mode: t
  eros-mode: t
  flymake-mode: t
  pdf-occur-global-minor-mode: t
  minibuffer-depth-indicate-mode: t
  repeat-mode: t
  display-time-mode: t
  display-battery-mode: t
  delete-selection-mode: t
  xterm-mouse-mode: t
  straight-use-package-mode: t
  straight-package-neutering-mode: t
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  show-paren-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  use-hard-newlines: t
  tab-bar-history-mode: t
  tab-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  undelete-frame-mode: t
  transient-mark-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  abbrev-mode: t

Load-path shadows:
/home/viz/lib/emacs/straight/build/transient/transient hides /home/viz/lib/ports/emacs/lisp/transient

Features:
(shadow emacsbug edebug disass apropos erc-pcomplete erc-goodies erc
erc-backend erc-networks erc-common erc-compat erc-loaddefs pcmpl-linux
tramp-cmds rfc2104 display-line-numbers cc-langs rng-xsd xsd-regexp
rng-cmpct nxml-mode-expansions rng-nxml rng-valid nxml-mode nxml-outln
nxml-rap skeleton ecomplete cc-awk ps-mode gnuplot-context gnuplot
info-look expand-region text-mode-expansions cc-mode-expansions
the-org-mode-expansions python-el-fgallina-expansions js-mode-expansions
html-mode-expansions css-mode-expansions er-basic-expansions
expand-region-core expand-region-custom mule-diag descr-text msb ffap
net-utils add-log rect org-datetree org-capture doct find-dired grep
tar-mode sql view ement-tabulated-room-list ement ement-notify
notifications ement-room dns pcmpl-gnu rcirc sqlite-mode arc-mode
archive-mode lua-mode ind-util thai-util thai-word mule-util
bug-reference shortdoc shr-color cl-print debug backtrace mhtml-mode
css-mode sgml-mode js c-ts-common gnus-dired dictionary
dictionary-connection olivetti tramp-archive tramp-gvfs nov esxml-query
ement-room-list ement-lib ement-api ement-structs plz ement-macros ewoc
taxy-magit-section magit-section taxy svg-lib persist flow-fill
smerge-mode gnus-cite qp mm-archive mail-extr textsec uni-scripts
idna-mapping ucs-normalize uni-confusable textsec-check gnus-async
gnus-bcklg gnus-ml nndoc nndraft nnmh nnfolder nnmaildir nnagent nnml
nnnil gnus-agent gnus-srvr gnus-score score-mode nnvirtual gnus-msg nntp
gnus-cache shell-command+ latexenc ox-odt rng-loc rng-uri rng-parse
rng-match rng-dt rng-util rng-pttrn nxml-parse nxml-ns nxml-enc xmltok
nxml-util ox-latex ox-icalendar org-agenda ox-html table ox-ascii
ox-publish ox image-file image-converter cus-start tabify man nroff-mode
wdired etags fileloop imenu-xref network-stream url-http url-gw nsm
url-cache url-auth avy flyspell ispell org-pdftools pdf-annot facemenu
org-noter org-num oc-basic org-element org-persist avl-tree generator
ob-gnuplot ob-fortran ob-python python compat ob-julia ob-C ob-shell
ob-racket async ob-async cdlatex texmathp org-attach org-id org-refile
ol-eww eww xdg url-queue mm-url ol-rmail ol-mhe ol-irc ol-info ol-gnus
nnselect gnus-art mm-uu mml2015 mm-view mml-smime smime gnutls dig
gnus-sum shr pixel-fill kinsoku url-file svg gnus-group gnus-undo
gnus-start gnus-dbus gnus-cloud nnimap nnmail mail-source utf7 nnoo
gnus-spec gnus-int gnus-range message sendmail yank-media puny rfc822
mml mml-sec epa epg rfc6068 epg-config mm-decode mm-bodies mm-encode
mail-parse rfc2231 rfc2047 rfc2045 ietf-drums mailabbrev gmm-utils
mailheader gnus-win gnus nnheader gnus-util mail-utils range mm-util
mail-prsvr ol-docview doc-view ol-bibtex bibtex ol-bbdb ol-w3m ol-doi
org-link-doi org-tempo tempo ol-man org ob ob-tangle ob-ref ob-lob
ob-table ob-exp org-macro org-src ob-comint org-pcomplete org-list
org-footnote org-faces org-entities ob-emacs-lisp ob-core ob-eval
org-cycle org-table ol org-fold org-fold-core org-keys oc org-loaddefs
org-version org-compat org-macs crm help-fns radix-tree ediff ediff-merg
ediff-mult ediff-wind ediff-diff ediff-help ediff-init ediff-util reveal
dired-aux cc-mode cc-fonts cc-guess cc-menus cc-cmds cc-styles cc-align
cc-engine cc-vars cc-defs noutline outline typo misc pulse color
csv-mode sort xref conf-mode recentf tree-widget vc-backup log-view
pcvs-util vc diff vc-git diff-mode vc-dispatcher misearch multi-isearch
dabbrev pcmpl-unix sh-script smie treesit executable tramp-sh
tramp-cache tramp trampver tramp-integration files-x time-stamp
tramp-loaddefs tramp-compat shell pcomplete parse-time iso8601 ls-lisp
cursor-sensor face-remap server paredit edmacro kmacro eros time-date
checkdoc lisp-mnt flymake-proc flymake project warnings thingatpt
wordel-autoloads sokoban-autoloads ement-autoloads transient-autoloads
svg-lib-autoloads taxy-magit-section-autoloads magit-section-autoloads
dash-autoloads taxy-autoloads persist-autoloads plz-autoloads
nov-autoloads esxml-autoloads kv-autoloads transmission-autoloads
csv-mode-autoloads lua-mode-autoloads nix-mode-autoloads
gnuplot-autoloads devdocs-autoloads julia-mode-autoloads
racket-mode-autoloads eros-autoloads writegood-mode-autoloads
siege-mode-autoloads paredit-autoloads puni-autoloads
expand-region-autoloads filladapt-autoloads compose scroll-other-window
org-pdftools-autoloads org-noter-autoloads change-env-autoloads
math-delimiters-autoloads doct-autoloads ob-async-autoloads
async-autoloads emacs-ob-racket-autoloads valign-autoloads
cdlatex-autoloads auctex-autoloads tex-site pdf-occur ibuf-ext ibuffer
ibuffer-loaddefs tablist advice tablist-filter semantic/wisent/comp
semantic/wisent semantic/wisent/wisent semantic/util-modes semantic/util
semantic semantic/tag semantic/lex semantic/fw mode-local find-func
cedet pdf-isearch let-alist pdf-misc imenu pdf-tools package browse-url
url url-proxy url-privacy url-expand url-methods url-history url-cookie
generate-lisp-file url-domsuf url-util mailcap url-handlers url-parse
auth-source eieio eieio-core json map byte-opt url-vars compile comint
ansi-osc ansi-color ring cus-edit wid-edit pdf-view password-cache
jka-compr pdf-cache pdf-info tq pdf-util pdf-macs image-mode dired-x
dired dired-loaddefs exif pdf-tools-autoloads tablist-autoloads
typo-autoloads mb-depth repeat visual-fill-autoloads olivetti-autoloads
time format-spec battery dbus filenotify xml dom tamil99 quail
disp-table lacarte-autoloads shell-command-plus-autoloads icons delsel
easy-mmode xt-mouse cus-load avy-autoloads icalendar diary-lib
diary-loaddefs cal-menu calendar cal-loaddefs dired-du-autoloads
finder-inf filecache imenu-xref-autoloads derived chemtable-autoloads
molar-mass-autoloads vc-backup-autoloads compat-autoloads
saveplace-pdf-view saveplace bookmark text-property-search pp
saveplace-pdf-view-autoloads rx pcase inspector-autoloads xr-autoloads
straight-autoloads cl-seq info cl-extra help-mode straight subr-x
cl-macs gv cl-loaddefs cl-lib bytecomp byte-compile vz-nh-theme
vz-options-theme rmc iso-transl tooltip cconv eldoc paren electric
uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel
term/x-win x-win term/common-win x-dnd tool-bar dnd fontset image
regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode
prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu
timer select scroll-bar mouse jit-lock font-lock syntax font-core
term/tty-colors frame minibuffer nadvice seq simple cl-generic
indonesian philippine cham georgian utf-8-lang misc-lang vietnamese
tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
composite emoji-zwj charscript charprop case-table epa-hook
jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs
theme-loaddefs faces cus-face macroexp files window text-properties
overlay sha1 md5 base64 format env code-pages mule custom widget keymap
hashtable-print-readable backquote threads dbusbind inotify
dynamic-setting system-font-setting font-render-setting x-toolkit
xinput2 x multi-tty make-network-process emacs)

Memory information:
((conses 16 3698457 420989)
 (symbols 48 71567 125)
 (strings 32 485043 37152)
 (string-bytes 1 42116953)
 (vectors 16 202430)
 (vector-slots 8 3912716 375269)
 (floats 8 1712 1293)
 (intervals 56 484153 8174)
 (buffers 976 252))