Subject: bug#76705: 31.0.50; igc: crash

From: Helmut Eller <[email-masked]>
Date: Wed, 05 Mar 2025 13:34:47 +0100

On Tue, Mar 04 2025, Pip Cet wrote:

> Gerd, Helmut, Eli:
>
> See https://github.com/Ravenbrook/mps/issues/304 for the description of
> a Linux-specific MPS issue that currently causes hard crashes when we
> create "too many" mappings for the Linux kernel (this is purely a kernel
> issue, so no GNU/ prefix here), which causes 'mprotect' to fail with
> ENOMEM.

For me, this code 
;; -*- lexical-binding: t -*-

(defun test ()
  (let* ((npages 120000)
	 (pages (make-vector npages nil)))
    (dotimes (i npages)
      (aset pages i (make-vector (/ 4096 2) 0)))
    (message "nmaps: %s" 
	     (shell-command-to-string
	      (format "wc -l /proc/%d/maps" (emacs-pid))))
    (dotimes (i npages)
      (when (zerop (% i 2))
	(let ((page (aref pages i)))
	  (aset page 0 1))))))

crashes with:
protix.c:117: Emacs fatal error: assertion failed: unreachable code

Though this seems to require >4GB.

> We have to find a workaround for this.

We could emit a warning (similar to [1]) and telling users to increase
max_map_count.  E.g. if COMMIT_LIMIT / PAGE_SIZE > max_map_count.

Increasing max_map_size seems pretty harmless[2] and the reason[3] why
it is so low, seems to be some no-longer relevant limit for core
dumps[3].

We could also set COMMIT_LIMIT to max_map_count / PAGE_SIZE, so that MPS
tries harder to reuse memory.  Beside issue #288[4], we would likely
see situations where MPS gets slower and slower because it can free some
memory but not enough to make much progress on non-GC tasks.

[1] https://alchemistsimulator.github.io/howtos/workarounds/max-map-count/index.html#symptoms
[2] https://www.suse.com/support/kb/doc/?id=000016692
[3] https://github.com/torvalds/linux/blob/v5.18/include/linux/mm.h#L178
[4] https://github.com/Ravenbrook/mps/issues/288

> Increasing AREA_GRAIN_SIZE may delay running into the problem, or there
> might be a way to handle a failed mprotect call and at least recover the
> Emacs session, but ultimately the maximum safe size of an Emacs session
> appears to be ARENA_GRAIN_SIZE * /proc/sys/vm/max_map_count, or about
> 512 MB of MPS memory (minus whatever mappings libraries, malloc, and
> mmap require).  That's obviously not sufficient.

My guess is that AREA_GRAIN_SIZE is used for mmap/mmunmap but the memory
barriers always work at page granularity.  I could be wrong of course.

> One open question is whether Linux is actually capable of merging
> adjacent mappings when they're 'mprotect'ed to have the same
> permissions.

That's easy to verify with the attached C code.  Without the second call
to change_protection, the number mappings increases until the process
aborts.

Helmut