Subject: 26.1.50; 27.0.50; Fatal error after re-evaluating a thread's function

From: Gemini Lasswell <[email-masked]>
Date: Wed, 10 Oct 2018 22:30:29 -0700

When I run some byte-compiled code which creates some threads, and then,
while a thread is blocked, interactively evaluate the function which
was used to create that thread, Emacs has a fatal error or segmentation
fault when the thread becomes unblocked.

To reproduce:

  Build Emacs from master with this patch, in which I've pasted some
  excerpts from my current project onto the end of lisp/thread.el.  It's
  going to be like ERT but designed to run benchmarks instead of tests,
  but right now all it does is to create a buffer and three threads, set
  the threads up to communicate with each other, log their progress to
  *Messages*, and update the buffer when they finish:

>From 4b9e3ccb2376ea532051d5ff7d2d308df56576c9 Mon Sep 17 00:00:00 2001
From: Gemini Lasswell <[email-masked]>
Date: Tue, 9 Oct 2018 09:27:54 -0700
Subject: [PATCH] Reproduce Bswitch segfault

---
 lisp/thread.el | 454 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 454 insertions(+)

diff --git a/lisp/thread.el b/lisp/thread.el
index 7974a2603c..9c4774e961 100644
--- a/lisp/thread.el
+++ b/lisp/thread.el
@@ -196,5 +196,459 @@ thread-list--name
       (and (eq thread main-thread) "Main")
       (prin1-to-string thread)))
 
+;;; Thread-safe messages
+
+(cl-defstruct
+    (thread--message
+     (:constructor
+      thread-make-message (&optional name
+                                     &aux
+                                     (mutex (make-mutex name))
+                                     (condition
+                                      (make-condition-variable mutex name)))))
+  name mutex value condition)
+
+(defun thread-message-available-p (message)
+  "Return the value of MESSAGE."
+  (thread--message-value message))
+
+(defun thread-message-send (message value)
+  "Set the VALUE of MESSAGE, and awaken all threads waiting for it."
+  (with-mutex (thread--message-mutex message)
+    (setf (thread--message-value message) value)
+    (condition-notify (thread--message-condition message) t)))
+
+(defun thread-message-cancel (message)
+  "Cancel MESSAGE by setting its value to nil."
+  (with-mutex (thread--message-mutex message)
+    (setf (thread--message-value message) nil)))
+
+(defun thread-message-wait (message &optional cancel)
+  "If MESSAGE's value is nil, block until it is set to something else.
+Return the value of MESSAGE.  If CANCEL is non-nil, clear MESSAGE
+by setting its value to nil.  If multiple threads are waiting on
+the same message, and all pass a non-nil CANCEL, then only one
+thread will unblock and receive the message's value, and the
+others will continue to block."
+  (with-mutex (thread--message-mutex message)
+    (while (not (thread--message-value message))
+      (condition-wait (thread--message-condition message)))
+    (let ((value (thread--message-value message)))
+      (when cancel
+        (setf (thread--message-value message) nil))
+      value)))
+
+;;; Thread-safe queues
+
+(cl-defstruct (thread--queue
+               (:constructor
+                thread-make-queue (&optional
+                                   size-limit
+                                   type
+                                   &aux
+                                   (fifo (eq type 'fifo))
+                                   (limit (when (natnump size-limit) size-limit))
+                                   (mutex (make-mutex))
+                                   (not-full (make-condition-variable mutex))
+                                   (not-empty (make-condition-variable mutex)))))
+  fifo
+  limit
+  items
+  mutex
+  not-full
+  not-empty)
+
+(defun thread-queue-empty-p (queue)
+  "Return non-nil if QUEUE is empty.
+There is no guarantee that QUEUE will contain the same number of
+items the next time you access it."
+  (with-mutex (thread--queue-mutex queue)
+    (null (thread--queue-items queue))))
+
+(defun thread-queue-full-p (queue)
+  "Return non-nil if QUEUE is full.
+There is no guarantee that QUEUE will contain the same number of
+items the next time you access it."
+  (when (thread--queue-limit queue)
+    (with-mutex (thread--queue-mutex queue)
+      (= (length (thread--queue-items queue)) (thread--queue-limit queue)))))
+
+(defun thread-queue-length (queue)
+  "Return the number of items in QUEUE.
+There is no guarantee that QUEUE will contain the same number of
+items the next time you access it."
+  (with-mutex (thread--queue-mutex queue)
+    (length (thread--queue-items queue))))
+
+(defun thread-queue-remove-all (queue)
+  "Discard any items in QUEUE."
+  (with-mutex (thread--queue-mutex queue)
+    (setf (thread--queue-items queue) nil)
+    (condition-notify (thread--queue-not-full queue))))
+
+(defun thread-queue-put (item queue)
+  "Put ITEM into QUEUE.
+If QUEUE was created with a size limit, and already contains that many items,
+block until one is removed."
+  (with-mutex (thread--queue-mutex queue)
+    (while (and (thread--queue-limit queue)
+                (= (length (thread--queue-items queue)) (thread--queue-limit queue)))
+      (condition-wait (thread--queue-not-full queue)))
+    (if (thread--queue-fifo queue)
+        (setf (thread--queue-items queue)
+              (nconc (thread--queue-items queue) (list item)))
+      (push item (thread--queue-items queue)))
+    (condition-notify (thread--queue-not-empty queue))))
+
+(defun thread-queue-get (queue)
+  "Remove an item from QUEUE and return it.
+If there are no items in QUEUE, block until one is added."
+  (with-mutex (thread--queue-mutex queue)
+    (while (null (thread--queue-items queue))
+      (condition-wait (thread--queue-not-empty queue)))
+    (let ((item (pop (thread--queue-items queue))))
+      (condition-notify (thread--queue-not-full queue))
+      item)))
+
+;;; Bswitch bug
+
+(require 'seq)
+
+(defvar erb--job (thread-make-message)
+  "This contains all the information needed about what benchmark job to run.
+It is created by `erb-run-start' and cleared when the benchmark job is
+finished by `erb-run--benchmarker'.")
+
+(defvar erb--status nil
+  "The state of the benchmark runner.
+Possible values are `idle', `building', `benchmarking' and
+`done'.  Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-commits nil
+  "The commits being processed by the benchmark runner.")
+
+(defvar erb--status-waiting-to-build nil
+  "The list of commits that have not yet started building.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-building nil
+  "The list of commits that are currently being built.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-built nil
+  "The list of commits that have been built.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-failed-builds nil
+  "The list of commits that failed to build.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-waiting-to-benchmark nil
+  "The commits that are built and waiting to be benchmarked.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-benchmarking nil
+  "The commit that is currently being benchmarked.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-benchmark-failures nil
+  "The commits that had task failures during benchmarking.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb--status-finished nil
+  "The commits that are finished benchmarking.
+Maintained by `erb-run--monitor' and used to update the
+`erb-run' buffer.")
+
+(defvar erb-run--cancel-request (thread-make-message)
+  "Signal the user's request that a benchmark job be stopped.
+Cleared when the benchmark job is cleaned up, by
+`erb-run-benchmarker'.")
+
+
+;;; ERB Run Benchmarks mode
+
+(defvar erb-run-refresh-seconds 0.2
+  "Delay between updates of `erb-run' buffers.")
+
+;; Options settable in the erb-run-mode buffer.
+(defvar-local erb-run--commit-range '("commitA" "commitB" "commitC"))
+(defvar-local erb-run--count-to-select nil)
+
+(defvar erb-run-mode-map
+  (let ((map (copy-keymap special-mode-map)))
+    (set-keymap-parent map button-buffer-map)
+    (define-key map "n" 'next-line)
+    (define-key map "p" 'previous-line)
+    (define-key map "s" 'erb-run-start)
+    (define-key map "c" 'erb-run-cancel)
+    (define-key map [follow-link] 'mouse-face)
+    (define-key map [mouse-2] 'mouse-select-window)
+
+    map)
+  "Local keymap for `erb-run-mode' buffers.")
+
+(define-derived-mode erb-run-mode special-mode "ERB-run"
+  "Mode for configuring and running benchmarks.
+\\<erb-run-mode-map>
+ERB is documented in info node `(erb)'."
+  :group 'erb-mode
+  (setq-local revert-buffer-function #'erb-run-revert-buffer))
+
+;; TODO make only one buffer?
+(defun erb-run-generate-new-buffer ()
+  (let* ((name (format "*ERB-run: %s*" (file-name-nondirectory
+                                        (directory-file-name default-directory))))
+         (buffer (generate-new-buffer name)))
+    (with-current-buffer buffer
+      (erb-run-mode)
+      (run-at-time erb-run-refresh-seconds nil
+                   #'erb-run--timer-func buffer)
+      (add-to-list 'uniquify-list-buffers-directory-modes 'erb-run-mode))
+    buffer))
+
+;; TODO autoload is just for now
+;;;###autoload
+(defun erb-summary-run ()
+  "Switch to or create an `erb-run-mode' buffer for running benchmarks."
+  (interactive)
+  (let* ((dir default-directory)
+         (buffer (or (seq-find (lambda (buf)
+                                 (with-current-buffer buf
+                                   (eq major-mode 'erb-run-mode)))
+                               (buffer-list))
+                     (erb-run-generate-new-buffer))))
+    (switch-to-buffer buffer)
+    (erb-run-revert-buffer buffer)))
+
+(defun erb-run-revert-buffer (&rest _ignored)
+  (let ((inhibit-read-only t))
+    (erase-buffer)
+    ;; (erb--update-config-cache)
+    (insert
+     (format "Commit range: %s\n" erb-run--commit-range)
+     (format "Number to select: %s\n" (if erb-run--count-to-select
+                                          erb-run--count-to-select "All"))
+     (if (memq erb--status '(idle done))
+         "\nStart running benchmarks\n"
+       "\nCancel\n")
+
+     "\n"
+     (format "Benchmarked: %s\n" (if erb--status-finished
+                                     (length erb--status-finished) ""))
+     (format "Build Failures: %s\n" (if (not (eq erb--status 'idle))
+                                        (length erb--status-failed-builds) ""))
+     (format "Task Failures: %s\n" (if (not (eq erb--status 'idle))
+                                       (length erb--status-benchmark-failures) ""))
+     "Total: %s/%s\n\n"
+
+     "Started at: \n"
+     (cl-case erb--status
+       (building "Building.")
+       (benchmarking "Benchmarking.")
+       (idle "Ready.")
+       (done "Finished.")
+       (t (format "erb--status=%s" erb--status)))
+     "\nFinished at: \n\n")
+
+    (unless (eq erb--status 'idle)
+      (dolist (commit erb--status-commits)
+        (insert
+         (cond
+          ((memq commit erb--status-finished)           ".")
+          ((memq commit erb--status-building)           "B")
+          ((memq commit erb--status-benchmark-failures) "F")
+          ((memq commit erb--status-failed-builds)      "E")
+          ((memq commit erb--status-benchmarking)       "@")
+          ((memq commit erb--status-built)              "b")
+          (t "w"))))
+      (insert "\n"))
+
+    (set-buffer-modified-p nil)))
+
+(defun erb-run--timer-func (buffer)
+  "Revert BUFFER and set a timer to do it again."
+  (when (buffer-live-p buffer)
+    (with-current-buffer buffer
+      (revert-buffer))
+    (run-at-time erb-run-refresh-seconds nil
+                 #'erb-run--timer-func buffer)))
+
+(defun erb-run-start ()
+  "Start running benchmarks."
+  (interactive)
+  (when (thread-message-available-p erb--job)
+    (user-error "Benchmarks are already running"))
+
+  (erb--start-benchmark-controller-thread)
+  (erb--start-builder-threads)
+  (erb--start-benchmark-monitor-thread)
+
+  (unless erb-run--commit-range
+    (user-error "Choose a commit or range of commits to benchmark"))
+
+  (erb--status-clear)
+  (thread-message-send erb--job erb-run--commit-range))
+
+(defun erb-run-cancel ()
+  "Stop running benchmarks."
+  (interactive)
+  (erb--status-clear))
+
+;;; The benchmark runner: the controller thread
+
+(defvar erb-simultaneous-build-count 1
+  "The number of builds to run simultaneously.")
+
+(defvar erb--builders nil
+  "The list of threads which have been created to run builds.")
+
+(defvar erb--unbuilt-commits (thread-make-queue)
+  "A thread-safe queue of commits waiting to be built.")
+(defvar erb--built-commits (thread-make-queue)
+  "A thread-safe queue of commits which have been built.")
+
+(defvar erb--benchmark-controller nil)
+
+(defun erb--start-benchmark-controller-thread ()
+  "Start the benchmark controller thread if it is not already started."
+  (unless erb--benchmark-controller
+    (setq erb--benchmark-controller
+          (make-thread #'erb--benchmark-control-func "control"))))
+
+(defun erb--benchmark-control-func ()
+  "Process benchmark jobs.
+Watch for incoming jobs arriving by a thread-safe message in
+`erb--job'.  When a job becomes available, build and
+benchmark all the commits and then clear the message."
+  (while t
+    (condition-case err
+        (let* ((job (thread-message-wait erb--job))
+               (count (length job))
+               builds)
+
+          ;; First, do all the builds.  There may be more than one
+          ;; builder thread.
+          (erb--status-change 'erb--status 'building)
+          (dolist (commit job)
+            (erb--status-add commit 'erb--status-waiting-to-build)
+            (thread-queue-put commit erb--unbuilt-commits))
+
+          (while (> count 0)
+            (let ((build (thread-queue-get erb--built-commits)))
+              (push build builds))
+            (cl-decf count))
+
+          (erb--status-change 'erb--status 'benchmarking)
+          ;; Then benchmark the build results, one at a time.
+
+          (erb--status-change 'erb--status 'done)
+          (thread-message-cancel erb--job))
+      ((error quit) (message "Error in ERB benchmark control thread: %s" err)))))
+
+;;; The benchmark runner: the builder threads
+
+;; TODO  Watch for a signal to shut down
+
+(defun erb--start-builder-threads ()
+  "Create the desired number of commit-building threads.
+Get the number from `erb-run-simultaneous-build-count'.
+TODO: adjust the number down as well as up."
+  (let ((needed (- erb-simultaneous-build-count
+                   (length erb--builders))))
+    (while (> needed 0)
+      (push (make-thread #'erb--builder-func
+                         (format "builder %s" (length erb--builders)))
+            erb--builders)
+      (cl-decf needed))))
+
+(defun erb--builder-func ()
+  "Build commits from `erb-run--commmits-to-build'."
+  (while t
+    (condition-case err
+        (let ((commit (thread-queue-get erb--unbuilt-commits)))
+          (message "building %s" commit)
+          (erb--status-remove commit 'erb--status-waiting-to-build)
+          (erb--status-add commit 'erb--status-building)
+
+          (unwind-protect
+              (sleep-for (random 10))
+
+            (erb--status-remove commit 'erb--status-building)
+            (erb--status-add commit 'erb--status-built)
+            (thread-queue-put commit erb--built-commits)))
+
+      ((error quit) (message "Error in ERB benchmark build thread: %s" err)))))
+
+;;; The benchmark runner: the status monitor thread
+
+(defvar erb--benchmark-monitor nil
+  "The thread which keeps track of build and benchmark job status.")
+(defvar erb--status-updates (thread-make-queue nil 'fifo)
+  "A thread-safe queue of status updates yet to be processed.")
+
+(defun erb--status-clear ()
+  (thread-queue-put '(clear) erb--status-updates))
+(defun erb--status-change (symbol value)
+  (thread-queue-put `(change ,symbol ,value) erb--status-updates))
+(defun erb--status-add (value symbol)
+  (thread-queue-put `(add ,value ,symbol) erb--status-updates))
+(defun erb--status-remove (value symbol)
+  (thread-queue-put `(remove ,value ,symbol) erb--status-updates))
+
+(defun erb--start-benchmark-monitor-thread ()
+  "Start the benchmark monitor thread if it is not already started."
+  (unless erb--benchmark-monitor
+    (setq erb--benchmark-monitor
+          (make-thread #'erb--benchmark-monitor-func "monitor"))))
+
+(defvar erb--logging t)
+(defun erb--benchmark-monitor-func ()
+  "Process benchmark job status update.
+Collect status update requests from `erb--status-updates'
+and update the various global variables accordingly."
+  (while t
+    (condition-case err
+        (pcase (thread-queue-get erb--status-updates)
+          (`(clear)
+           (when erb--logging (message "** Clear **"))
+           (erb--clear-status))
+          (`(add ,value ,variable)
+           (when erb--logging
+             (message "** Add %s to %s **" value variable))
+           (push value (symbol-value variable)))
+          (`(remove ,value ,variable)
+           (when erb--logging
+             (message "** Remove %s from %s **" value variable))
+           (setf (symbol-value variable)
+                 (delq value (symbol-value variable))))
+          (`(change ,variable ,value)
+           (when erb--logging
+             (message "** Set %s to %s **" variable value))
+           (setf (symbol-value variable) value))
+          (update (error "Unrecognized status update: %s" update)))
+      ((error quit) (message "Error in ERB benchmark control thread: %s" err)))))
+
+(defun erb--clear-status ()
+  "Reset all the ERB benchmarking status variables to their initial state."
+  (setq erb--status                      'idle
+        erb--status-waiting-to-build     nil
+        erb--status-building             nil
+        erb--status-built                nil
+        erb--status-failed-builds        nil
+        erb--status-waiting-to-benchmark nil
+        erb--status-benchmarking         nil
+        erb--status-finished             nil))
+
+
+
 (provide 'thread)
 ;;; thread.el ends here
-- 
2.16.4

  Run Emacs with -Q, and then type:
    M-x erb-summary-run RET
    s

  Wait several seconds for the second to the last line in the buffer to
  change to "Finished".  There will also be an echo area message about
  erb--status being set to done.

  Navigate to lisp/thread.el, select everything from the definition of
  erb--benchmark-monitor to the end of the file, and use:
    M-x eval-region RET

  Return to the buffer created by erb-summary-run, and type 's' again.

Result:

lisp.h:2241: Emacs fatal error: assertion failed: HASH_TABLE_P (a)

My suspicion is that the garbage collector is freeing something needed
by the blocked thread.  Setting gc-cons-threshold to 500M before doing
the steps above stops the error from happening.

Here's the backtrace.  While trying to sort out how to reproduce this, I
also saw it segfault in Ffuncall, in styled_format, and in the Bswitch
case of exec_byte_code just past where this error occurs, when it tries
to access h->count.

Thread 7 (Thread 0x7f1cd4dec700 (LWP 21837)):
#0  terminate_due_to_signal (sig=sig@entry=6,
    backtrace_limit=backtrace_limit@entry=2147483647) at emacs.c:369
#1  0x00000000005a4d99 in die (msg=msg@entry=0x678d52 "HASH_TABLE_P (a)",
    file=file@entry=0x6768a5 "lisp.h", line=line@entry=2241) at alloc.c:7094
#2  0x00000000006122b5 in XHASH_TABLE (a=...) at lisp.h:2241
#3  exec_byte_code (bytestr=..., vector=..., maxdepth=..., args_template=...,
    nargs=nargs@entry=0, args=<optimized out>,
    args@entry=0x16eac38 <bss_sbrk_buffer+9926040>) at bytecode.c:1403
#4  0x00000000005cb972 in funcall_lambda (fun=..., nargs=nargs@entry=0,
    arg_vector=0x16eac38 <bss_sbrk_buffer+9926040>,
    arg_vector@entry=0x158ec58 <bss_sbrk_buffer+8500664>) at eval.c:3057
#5  0x00000000005c818b in Ffuncall (nargs=nargs@entry=1,
    args=args@entry=0x158ec50 <bss_sbrk_buffer+8500656>) at eval.c:2870
#6  0x000000000064443b in invoke_thread_function () at thread.c:684
#7  0x00000000005c728f in internal_condition_case (
    bfun=bfun@entry=0x644400 <invoke_thread_function>, handlers=...,
    handlers@entry=XIL(0xc3c0), hfun=hfun@entry=0x644320 <record_thread_error>)
    at eval.c:1373
#8  0x0000000000644dd1 in run_thread (state=0x158ec30 <bss_sbrk_buffer+8500624>)
    at thread.c:723
#9  0x00007f1cebf602a7 in start_thread ()
   from /nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131/lib/libpthread.so.0
#10 0x00007f1ceb5fd57f in clone ()
   from /nix/store/hwwqshlmazzjzj7yhrkyjydxamvvkfd3-glibc-2.26-131/lib/libc.so.6

Thread 7 (Thread 0x7f1cd4dec700 (LWP 21837)):
"erb--benchmark-monitor-func" (0x158ec58)

In GNU Emacs 27.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.22.28)
 of 2018-10-09 built on sockeye
Repository revision: 708444efad7a2ce1e309532898b844527e2d9c64
Windowing system distributor 'The X.Org Foundation', version 11.0.11906000
System Description: NixOS 18.03.git.bd06547 (Impala)

Recent messages:
For information about GNU Emacs and the GNU system, type C-h C-a.

Configured using:
 'configure --prefix=/home/gem/src/emacs/master/bin --with-modules
 --with-x-toolkit=gtk3 --with-xft --config-cache
 --enable-checking=yes,glyphs --enable-check-lisp-object-type'

Configured features:
XPM JPEG TIFF GIF PNG RSVG SOUND DBUS GSETTINGS GLIB NOTIFY LIBSELINUX
GNUTLS LIBXML2 FREETYPE XFT ZLIB TOOLKIT_SCROLL_BARS GTK3 X11 XDBE XIM
MODULES THREADS GMP

Important settings:
  value of $EMACSLOADPATH:
  value of $LANG: en_US.UTF-8
  locale-coding-system: utf-8-unix

Major mode: Lisp Interaction

Minor modes in effect:
  tooltip-mode: t
  global-eldoc-mode: t
  eldoc-mode: t
  electric-indent-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t

Load-path shadows:
None found.

Features:
(shadow sort mail-extr emacsbug message rmc puny seq byte-opt gv
bytecomp byte-compile cconv dired dired-loaddefs format-spec rfc822 mml
easymenu mml-sec password-cache epa derived epg epg-config gnus-util
rmail rmail-loaddefs time-date mm-decode mm-bodies mm-encode mail-parse
rfc2231 mailabbrev gmm-utils mailheader cl-loaddefs cl-lib sendmail
rfc2047 rfc2045 ietf-drums mm-util mail-prsvr mail-utils elec-pair
mule-util tooltip eldoc electric uniquify ediff-hook vc-hooks
lisp-float-type 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 elisp-mode lisp-mode prog-mode register page menu-bar
rfn-eshadow isearch timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core term/tty-colors frame cl-generic 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 charscript charprop
case-table epa-hook jka-cmpr-hook help simple abbrev obarray minibuffer
cl-preloaded nadvice loaddefs button faces cus-face macroexp files
text-properties overlay sha1 md5 base64 format env code-pages mule
custom widget hashtable-print-readable backquote threads dbusbind
inotify dynamic-setting system-font-setting font-render-setting
move-toolbar gtk x-toolkit x multi-tty make-network-process emacs)

Memory information:
((conses 16 94967 9472)
 (symbols 48 20045 1)
 (strings 32 28456 1769)
 (string-bytes 1 816313)
 (vectors 16 14265)
 (vector-slots 8 504082 12268)
 (floats 8 47 70)
 (intervals 56 213 0)
 (buffers 992 11))