diff options
| author | Stefan Monnier | 2022-02-22 10:18:43 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2022-02-22 10:18:43 -0500 |
| commit | 4bd7963e2e244ace94afa59124f2637543d74ba2 (patch) | |
| tree | 01c8ae1f66cdaa307448fbcd7fcb79081fb87d7f | |
| parent | 09bd220d865520f2426ae99d97b8b8296058732f (diff) | |
| download | emacs-4bd7963e2e244ace94afa59124f2637543d74ba2.tar.gz emacs-4bd7963e2e244ace94afa59124f2637543d74ba2.zip | |
(add-hook, remove-hook): Fix leaks (bug#48666)
* lisp/subr.el (add-hook, remove-hook): Rewrite the hook depth
management so we only keep the info relevant to functions present on
the hook.
| -rw-r--r-- | lisp/subr.el | 65 |
1 files changed, 39 insertions, 26 deletions
diff --git a/lisp/subr.el b/lisp/subr.el index a78af09c40e..1b9b67b7054 100644 --- a/lisp/subr.el +++ b/lisp/subr.el | |||
| @@ -1913,26 +1913,34 @@ performance impact when running `add-hook' and `remove-hook'." | |||
| 1913 | (setq hook-value (list hook-value))) | 1913 | (setq hook-value (list hook-value))) |
| 1914 | ;; Do the actual addition if necessary | 1914 | ;; Do the actual addition if necessary |
| 1915 | (unless (member function hook-value) | 1915 | (unless (member function hook-value) |
| 1916 | (when (stringp function) ;FIXME: Why? | 1916 | (let ((depth-sym (get hook 'hook--depth-alist))) |
| 1917 | (setq function (purecopy function))) | 1917 | ;; While the `member' test above has to use `equal' for historical |
| 1918 | ;; All those `equal' tests performed between functions can end up being | 1918 | ;; reasons, `equal' is a performance problem on large/cyclic functions, |
| 1919 | ;; costly since those functions may be large recursive and even cyclic | 1919 | ;; so we index `hook--depth-alist' with `eql'. (bug#46326) |
| 1920 | ;; structures, so we index `hook--depth-alist' with `eq'. (bug#46326) | 1920 | (unless (zerop depth) |
| 1921 | (when (or (get hook 'hook--depth-alist) (not (zerop depth))) | 1921 | (unless depth-sym |
| 1922 | ;; Note: The main purpose of the above `when' test is to avoid running | 1922 | (setq depth-sym (make-symbol "depth-alist")) |
| 1923 | ;; this `setf' before `gv' is loaded during bootstrap. | 1923 | (set depth-sym nil) |
| 1924 | (setf (alist-get function (get hook 'hook--depth-alist) 0) depth)) | 1924 | (setf (get hook 'hook--depth-alist) depth-sym)) |
| 1925 | (setq hook-value | 1925 | (if local (make-local-variable depth-sym)) |
| 1926 | (if (< 0 depth) | 1926 | (setf (alist-get function |
| 1927 | (append hook-value (list function)) | 1927 | (if local (symbol-value depth-sym) |
| 1928 | (cons function hook-value))) | 1928 | (default-value depth-sym)) |
| 1929 | (let ((depth-alist (get hook 'hook--depth-alist))) | 1929 | 0) |
| 1930 | (when depth-alist | 1930 | depth)) |
| 1931 | (setq hook-value | 1931 | (setq hook-value |
| 1932 | (sort (if (< 0 depth) hook-value (copy-sequence hook-value)) | 1932 | (if (< 0 depth) |
| 1933 | (lambda (f1 f2) | 1933 | (append hook-value (list function)) |
| 1934 | (< (alist-get f1 depth-alist 0 nil #'eq) | 1934 | (cons function hook-value))) |
| 1935 | (alist-get f2 depth-alist 0 nil #'eq)))))))) | 1935 | (when depth-sym |
| 1936 | (let ((depth-alist (if local (symbol-value depth-sym) | ||
| 1937 | (default-value depth-sym)))) | ||
| 1938 | (when depth-alist | ||
| 1939 | (setq hook-value | ||
| 1940 | (sort (if (< 0 depth) hook-value (copy-sequence hook-value)) | ||
| 1941 | (lambda (f1 f2) | ||
| 1942 | (< (alist-get f1 depth-alist 0 nil #'eq) | ||
| 1943 | (alist-get f2 depth-alist 0 nil #'eq)))))))))) | ||
| 1936 | ;; Set the actual variable | 1944 | ;; Set the actual variable |
| 1937 | (if local | 1945 | (if local |
| 1938 | (progn | 1946 | (progn |
| @@ -2005,9 +2013,14 @@ one will be removed." | |||
| 2005 | (when old-fun | 2013 | (when old-fun |
| 2006 | ;; Remove auxiliary depth info to avoid leaks (bug#46414) | 2014 | ;; Remove auxiliary depth info to avoid leaks (bug#46414) |
| 2007 | ;; and to avoid the list growing too long. | 2015 | ;; and to avoid the list growing too long. |
| 2008 | (let* ((depths (get hook 'hook--depth-alist)) | 2016 | (let* ((depth-sym (get hook 'hook--depth-alist)) |
| 2009 | (di (assq old-fun depths))) | 2017 | (depth-alist (if depth-sym (if local (symbol-value depth-sym) |
| 2010 | (when di (put hook 'hook--depth-alist (delq di depths))))) | 2018 | (default-value depth-sym)))) |
| 2019 | (di (assq old-fun depth-alist))) | ||
| 2020 | (when di | ||
| 2021 | (setf (if local (symbol-value depth-sym) | ||
| 2022 | (default-value depth-sym)) | ||
| 2023 | (delq di depth-alist))))) | ||
| 2011 | ;; If the function is on the global hook, we need to shadow it locally | 2024 | ;; If the function is on the global hook, we need to shadow it locally |
| 2012 | ;;(when (and local (member function (default-value hook)) | 2025 | ;;(when (and local (member function (default-value hook)) |
| 2013 | ;; (not (member (cons 'not function) hook-value))) | 2026 | ;; (not (member (cons 'not function) hook-value))) |
| @@ -2169,7 +2182,7 @@ can do the job." | |||
| 2169 | (not (macroexp-const-p append))) | 2182 | (not (macroexp-const-p append))) |
| 2170 | exp | 2183 | exp |
| 2171 | (let* ((sym (cadr list-var)) | 2184 | (let* ((sym (cadr list-var)) |
| 2172 | (append (eval append)) | 2185 | (append (eval append lexical-binding)) |
| 2173 | (msg (format-message | 2186 | (msg (format-message |
| 2174 | "`add-to-list' can't use lexical var `%s'; use `push' or `cl-pushnew'" | 2187 | "`add-to-list' can't use lexical var `%s'; use `push' or `cl-pushnew'" |
| 2175 | sym)) | 2188 | sym)) |
| @@ -2718,7 +2731,7 @@ It can be retrieved with `(process-get PROCESS PROPNAME)'." | |||
| 2718 | 2731 | ||
| 2719 | (defconst read-key-full-map | 2732 | (defconst read-key-full-map |
| 2720 | (let ((map (make-sparse-keymap))) | 2733 | (let ((map (make-sparse-keymap))) |
| 2721 | (define-key map [t] 'dummy) | 2734 | (define-key map [t] #'ignore) ;Dummy binding. |
| 2722 | 2735 | ||
| 2723 | ;; ESC needs to be unbound so that escape sequences in | 2736 | ;; ESC needs to be unbound so that escape sequences in |
| 2724 | ;; `input-decode-map' are still processed by `read-key-sequence'. | 2737 | ;; `input-decode-map' are still processed by `read-key-sequence'. |
| @@ -4471,7 +4484,7 @@ is allowed once again. (Immediately, if `inhibit-quit' is nil.)" | |||
| 4471 | ;; Without this, it will not be handled until the next function | 4484 | ;; Without this, it will not be handled until the next function |
| 4472 | ;; call, and that might allow it to exit thru a condition-case | 4485 | ;; call, and that might allow it to exit thru a condition-case |
| 4473 | ;; that intends to handle the quit signal next time. | 4486 | ;; that intends to handle the quit signal next time. |
| 4474 | (eval '(ignore nil))))) | 4487 | (eval '(ignore nil) t)))) |
| 4475 | 4488 | ||
| 4476 | (defmacro while-no-input (&rest body) | 4489 | (defmacro while-no-input (&rest body) |
| 4477 | "Execute BODY only as long as there's no pending input. | 4490 | "Execute BODY only as long as there's no pending input. |