From 1e2b653b3b4af5f19f24b700bdd55cb30c198670 Mon Sep 17 00:00:00 2001 From: "F. Jason Park" Date: Tue, 17 Oct 2023 23:36:12 -0700 Subject: [PATCH] [5.6] Warn about top-level erc-update-modules calls * doc/misc/erc.texi (Modules): Mention risk of infinite recursion when packages run `erc-update-modules' on load. * lisp/erc/erc.el (erc--warn-about-aberrant-modules): Tweak warning message. (erc--requiring-module-mode-p): New internal variable. (erc--find-mode): Guard against recursive `require's. (Bug#57955) --- doc/misc/erc.texi | 21 ++++++++++++--------- lisp/erc/erc.el | 21 ++++++++++++++++----- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/doc/misc/erc.texi b/doc/misc/erc.texi index 3bfa240cacc..c654c97731c 100644 --- a/doc/misc/erc.texi +++ b/doc/misc/erc.texi @@ -666,17 +666,17 @@ Modules @code{} in @code{erc-modules} lacks a corresponding @code{erc--mode} command, ERC will attempt to load the library @code{erc-} prior to connecting. If this fails, ERC signals an -error. Users wanting to define modules in an init files should +error. Users defining personal modules in an init file should @code{(provide 'erc-)} somewhere to placate ERC. Dynamically generating modules on the fly is not supported. -Sometimes, packages attempt to autoload a module's definition instead -of its minor-mode command, which breaks the link between the library -and the module. This means that enabling the mode by invoking its -command toggle isn't enough to load its defining library. Such -packages should instead only supply autoload cookies featuring an -explicit @code{autoload} form for their module's minor-mode command. -As mentioned above, packages can also usually avoid autoload cookies +Some packages attempt to autoload a module's definition instead of its +minor-mode command, which breaks the link between the library and the +module. This means that enabling the mode by invoking its command +toggle isn't enough to load its defining library. Such packages +should instead only supply autoload cookies featuring an explicit +@code{autoload} form for their module's minor-mode command. As +mentioned above, packages can also usually avoid autoload cookies entirely so long as their module's prefixed name matches that of its defining library and the latter's provided feature. @@ -686,7 +686,10 @@ Modules itself in an autoloaded form. Doing this tricks Customize into displaying the widget for @code{erc-modules} incorrectly, with built-in modules moved from the predefined checklist to the -user-provided free-form area. +user-provided free-form area. Similarly, some packages run +@code{erc-update-modules} in top-level and autoloaded forms or in +@code{after-load-functions} members, which can trigger recursive +invocations. @c PRE5_4: Document every option of every module in its own subnode diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el index 5bf6496e926..f841e385ab7 100644 --- a/lisp/erc/erc.el +++ b/lisp/erc/erc.el @@ -2129,12 +2129,17 @@ erc--aberrant-modules (defun erc--warn-about-aberrant-modules () (when (and erc--aberrant-modules (not erc--target)) (erc-button--display-error-notice-with-keys-and-warn - "The following modules exhibited strange loading behavior: " + "The following modules exhibit strange loading behavior: " (mapconcat (lambda (s) (format "`%s'" s)) erc--aberrant-modules ", ") ". Please contact ERC with \\[erc-bug] if you believe this to be untrue." " See Info:\"(erc) Module Loading\" for more.") (setq erc--aberrant-modules nil))) +(defvar erc--requiring-module-mode-p nil + "Non-nil when `require'ing `erc-mymod' from `erc-update-modules'. +Used for detecting top-level calls to `erc-update-modules' by +third-party packages.") + (defun erc--find-mode (sym) (setq sym (erc--normalize-module-symbol sym)) (if-let ((mode (intern-soft (concat "erc-" (symbol-name sym) "-mode"))) @@ -2144,10 +2149,16 @@ erc--find-mode (symbol-file mode) (ignore (cl-pushnew sym erc--aberrant-modules))))) mode - (and (require (or (get sym 'erc--feature) - (intern (concat "erc-" (symbol-name sym)))) - nil 'noerror) - (setq mode (intern-soft (concat "erc-" (symbol-name sym) "-mode"))) + (and (or (and erc--requiring-module-mode-p + ;; Also likely non-nil: (eq sym (car features)) + (cl-pushnew sym erc--aberrant-modules)) + (let ((erc--requiring-module-mode-p t)) + (require (or (get sym 'erc--feature) + (intern (concat "erc-" (symbol-name sym)))) + nil 'noerror)) + (memq sym erc--aberrant-modules)) + (or mode (setq mode (intern-soft (concat "erc-" (symbol-name sym) + "-mode")))) (fboundp mode) mode))) -- 2.41.0