Avoid fork bomb caused by native compilation
authorAndrea Corallo <akrl@sdf.org>
Fri, 14 Oct 2022 22:59:55 +0000 (00:59 +0200)
committerSean Whitton <spwhitton@spwhitton.name>
Wed, 26 Oct 2022 01:38:40 +0000 (18:38 -0700)
This upstream patch has been incorporated to fix the problem:

  Prevent potential native compilation infinite recursions

  * lisp/emacs-lisp/comp.el (comp-no-spawn): New var.
  (comp-subr-trampoline-install, comp-final, comp-run-async-workers)
  (comp--native-compile): Update.

Origin: upstream, commit: 1a8015b83761f27d299b1ffa45fc045bb76daf8a
Bug-Debian: https://bugs.debian.org/1017817
Bug-Debian: https://bugs.debian.org/1017845
Forwarded: not-needed

lisp/emacs-lisp/comp.el

index a5ab12ae38859ab3c9fe581a1c324723326fff37..dc94b907cfbdb764631112f7c944a0b8c743fadd 100644 (file)
@@ -676,6 +676,9 @@ Useful to hook into pass checkers.")
   'native-compiler-error)
 \f
 
+(defvar comp-no-spawn nil
+  "Non-nil don't spawn native compilation processes.")
+
 ;; Moved early to avoid circularity when comp.el is loaded and
 ;; `macroexpand' needs to be advised (bug#47049).
 ;;;###autoload
@@ -685,12 +688,9 @@ Useful to hook into pass checkers.")
               (memq subr-name native-comp-never-optimize-functions)
               (gethash subr-name comp-installed-trampolines-h))
     (cl-assert (subr-primitive-p (symbol-function subr-name)))
-    (comp--install-trampoline
-     subr-name
-     (or (comp-trampoline-search subr-name)
-         (comp-trampoline-compile subr-name)
-         ;; Should never happen.
-         (cl-assert nil)))))
+    (when-let ((trampoline (or (comp-trampoline-search subr-name)
+                               (comp-trampoline-compile subr-name))))
+      (comp--install-trampoline subr-name trampoline))))
 
 \f
 (cl-defstruct (comp-vec (:copier nil))
@@ -3680,7 +3680,8 @@ Prepare every function for final compilation and drive the C back-end."
              (print-circle t)
              (print-escape-multibyte t)
              (expr `((require 'comp)
-                     (setf native-comp-verbose ,native-comp-verbose
+                     (setf comp-no-spawn t
+                           native-comp-verbose ,native-comp-verbose
                            comp-libgccjit-reproducer ,comp-libgccjit-reproducer
                            comp-ctxt ,comp-ctxt
                            native-comp-eln-load-path ',native-comp-eln-load-path
@@ -3942,6 +3943,7 @@ display a message."
                                  native-comp-verbose ,native-comp-verbose
                                  comp-libgccjit-reproducer ,comp-libgccjit-reproducer
                                  comp-async-compilation t
+                                 comp-no-spawn t
                                  native-comp-eln-load-path ',native-comp-eln-load-path
                                  native-comp-compiler-options
                                  ',native-comp-compiler-options
@@ -4020,57 +4022,58 @@ the deferred compilation mechanism."
               (stringp function-or-file))
     (signal 'native-compiler-error
             (list "Not a function symbol or file" function-or-file)))
-  (catch 'no-native-compile
-    (let* ((data function-or-file)
-           (comp-native-compiling t)
-           (byte-native-qualities nil)
-           ;; Have byte compiler signal an error when compilation fails.
-           (byte-compile-debug t)
-           (comp-ctxt (make-comp-ctxt :output output
-                                      :with-late-load with-late-load)))
-      (comp-log "\n\f\n" 1)
-      (condition-case err
-          (cl-loop
-           with report = nil
-           for t0 = (current-time)
-           for pass in comp-passes
-           unless (memq pass comp-disabled-passes)
-           do
-           (comp-log (format "(%s) Running pass %s:\n"
-                             function-or-file pass)
-                     2)
-           (setf data (funcall pass data))
-           (push (cons pass (float-time (time-since t0))) report)
-           (cl-loop for f in (alist-get pass comp-post-pass-hooks)
-                    do (funcall f data))
-           finally
-           (when comp-log-time-report
-             (comp-log (format "Done compiling %s" data) 0)
-             (cl-loop for (pass . time) in (reverse report)
-                      do (comp-log (format "Pass %s took: %fs." pass time) 0))))
-        (native-compiler-skip)
-        (t
-         (let ((err-val (cdr err)))
-           ;; If we are doing an async native compilation print the
-           ;; error in the correct format so is parsable and abort.
-           (if (and comp-async-compilation
-                    (not (eq (car err) 'native-compiler-error)))
-               (progn
-                 (message (if err-val
-                              "%s: Error: %s %s"
-                            "%s: Error %s")
-                          function-or-file
-                          (get (car err) 'error-message)
-                          (car-safe err-val))
-                 (kill-emacs -1))
-             ;; Otherwise re-signal it adding the compilation input.
-            (signal (car err) (if (consp err-val)
-                                  (cons function-or-file err-val)
-                                (list function-or-file err-val)))))))
-      (if (stringp function-or-file)
-          data
-        ;; So we return the compiled function.
-        (native-elisp-load data)))))
+  (unless comp-no-spawn
+    (catch 'no-native-compile
+      (let* ((data function-or-file)
+             (comp-native-compiling t)
+             (byte-native-qualities nil)
+             ;; Have byte compiler signal an error when compilation fails.
+             (byte-compile-debug t)
+             (comp-ctxt (make-comp-ctxt :output output
+                                        :with-late-load with-late-load)))
+        (comp-log "\n\f\n" 1)
+        (condition-case err
+            (cl-loop
+             with report = nil
+             for t0 = (current-time)
+             for pass in comp-passes
+             unless (memq pass comp-disabled-passes)
+             do
+             (comp-log (format "(%s) Running pass %s:\n"
+                               function-or-file pass)
+                       2)
+             (setf data (funcall pass data))
+             (push (cons pass (float-time (time-since t0))) report)
+             (cl-loop for f in (alist-get pass comp-post-pass-hooks)
+                      do (funcall f data))
+             finally
+             (when comp-log-time-report
+               (comp-log (format "Done compiling %s" data) 0)
+               (cl-loop for (pass . time) in (reverse report)
+                        do (comp-log (format "Pass %s took: %fs." pass time) 0))))
+          (native-compiler-skip)
+          (t
+           (let ((err-val (cdr err)))
+             ;; If we are doing an async native compilation print the
+             ;; error in the correct format so is parsable and abort.
+             (if (and comp-async-compilation
+                      (not (eq (car err) 'native-compiler-error)))
+                 (progn
+                   (message (if err-val
+                                "%s: Error: %s %s"
+                              "%s: Error %s")
+                            function-or-file
+                            (get (car err) 'error-message)
+                            (car-safe err-val))
+                   (kill-emacs -1))
+               ;; Otherwise re-signal it adding the compilation input.
+              (signal (car err) (if (consp err-val)
+                                    (cons function-or-file err-val)
+                                  (list function-or-file err-val)))))))
+        (if (stringp function-or-file)
+            data
+          ;; So we return the compiled function.
+          (native-elisp-load data))))))
 
 (defun native-compile-async-skip-p (file load selector)
   "Return non-nil if FILE's compilation should be skipped.
@@ -4180,14 +4183,13 @@ Search happens in `native-comp-eln-load-path'."
 (defun native-compile (function-or-file &optional output)
   "Compile FUNCTION-OR-FILE into native code.
 This is the synchronous entry-point for the Emacs Lisp native
-compiler.
-FUNCTION-OR-FILE is a function symbol, a form, or the filename of
-an Emacs Lisp source file.
-If OUTPUT is non-nil, use it as the filename for the compiled
-object.
-If FUNCTION-OR-FILE is a filename, return the filename of the
-compiled object.  If FUNCTION-OR-FILE is a function symbol or a
-form, return the compiled function."
+compiler.  FUNCTION-OR-FILE is a function symbol, a form, or the
+filename of an Emacs Lisp source file.  If OUTPUT is non-nil, use
+it as the filename for the compiled object.  If FUNCTION-OR-FILE
+is a filename, if the compilation was successful return the
+filename of the compiled object.  If FUNCTION-OR-FILE is a
+function symbol or a form, if the compilation was successful
+return the compiled function."
   (comp--native-compile function-or-file nil output))
 
 ;;;###autoload