Subject: NetBSD: JIT doesn't work

From: Thomas Klausner <[email-masked]>
Date: Sat, 4 Mar 2023 09:02:53 +0100

Hi!

guile 3.0.9 on NetBSD 10.99.2/amd64 defaults to enabling the JIT,
butthen fails to build with:

  CCLD     libguile-3.0.la
ld: .libs/libguile_3.0_la-posix.o: in function `scm_tmpnam':
/scratch/lang/guile30/work/guile-3.0.9/libguile/posix.c:1757: warning: warning: tmpnam() possibly used unsafely, use mkstemp() or mkdtemp()
  CCLD     guile
ld: ./.libs/libguile-3.0.so: warning: warning: tmpnam() possibly used unsafely, use mkstemp() or mkdtemp()
  GEN      guile-procedures.texi
allocating JIT code buffer failed: Permission denied
jit.c:5896: fatal: assertion failed
cat: stdout: Broken pipe
[1]   Done(1)                 cat alist.doc array-handle.doc array-map.doc a... |
      Abort trap (core dumped) GUILE_AUTO_COMPILE=0 ../meta/build-env guild s...
gmake[3]: *** [Makefile:4657: guile-procedures.texi] Error 1

The underlying problem is that NetBSD by default has PaX MPROTECT
enabled, i.e. a page can not be mapped executable and writable at the
same time, which libguile/jit.c tries to do:

  ret->base = mmap (NULL, ret->size,
                    PROT_EXEC | PROT_READ | PROT_WRITE,
                    flags, -1, 0);

On NetBSD (and some other systems) the workaround is to map the page
twice - once writable, and once executable. The NetBSD mremap(2) man
page describes this and has a complete code example:

https://man.netbsd.org/mremap.2

Please add support for this to guile's JIT.

Thank you!
 Thomas

(Please note that there currently is a bug in NetBSD when using fork()
in such a situation, see https://gnats.netbsd.org/55177 for details. A
workaround is to map the page MAP_SHARED even though conceptually
MAP_PRIVATE would be correct.)