GNU bug report logs - #47429
allocating JIT code buffer failed: Permission denied

Previous Next

Package: guile;

Reported by: noloader <at> gmail.com

Date: Fri, 26 Mar 2021 22:49:02 UTC

Severity: normal

To reply to this bug, email your comments to 47429 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-guile <at> gnu.org:
bug#47429; Package guile. (Fri, 26 Mar 2021 22:49:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to noloader <at> gmail.com:
New bug report received and forwarded. Copy sent to bug-guile <at> gnu.org. (Fri, 26 Mar 2021 22:49:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: Jeffrey Walton <noloader <at> gmail.com>
To: bug-guile <at> gnu.org
Subject: allocating JIT code buffer failed: Permission denied
Date: Fri, 26 Mar 2021 18:48:22 -0400
[Message part 1 (text/plain, inline)]
Hi Everyone,

I'm building Guile 3.0.5 on OS X 11.2.3. It looks like Guile is having
some trouble:

libtool: link: /usr/bin/clang -std=gnu11 -I/usr/local/include
-D_THREAD_SAFE -Wall -Wmissing-prototypes -Wpointer-arith
-fno-strict-aliasing -fwrapv -fvisibility=hidden -I/usr/local/include
-g2 -O2 -fno-common -arch arm64 -fPIC -pthread -I/usr/local/include
-D_THREAD_SAFE -Wl,-rpath -Wl,@loader_path/../lib -Wl,-rpath
-Wl,/usr/local/lib -o .libs/guile guile-guile.o  -L/usr/local/lib
./.libs/libguile-3.0.dylib /usr/local/lib/libgc.dylib
/usr/local/lib/libffi.dylib /usr/local/lib/libintl.dylib
/usr/local/lib/libunistring.dylib /usr/local/lib/libiconv.dylib
/usr/local/lib/libgmp.dylib /usr/local/lib/libltdl.dylib -ldl
-lpthread -pthread
cat alist.doc array-handle.doc array-map.doc arrays.doc async.doc
atomic.doc backtrace.doc boolean.doc bitvectors.doc bytevectors.doc
chars.doc control.doc continuations.doc debug.doc deprecated.doc
deprecation.doc dynl.doc dynwind.doc eq.doc error.doc eval.doc
evalext.doc exceptions.doc expand.doc extensions.doc
fdes-finalizers.doc feature.doc filesys.doc fluids.doc foreign.doc
fports.doc gc-malloc.doc gc.doc gettext.doc generalized-arrays.doc
generalized-vectors.doc goops.doc gsubr.doc guardians.doc hash.doc
hashtab.doc hooks.doc i18n.doc init.doc ioext.doc keywords.doc
list.doc load.doc macros.doc mallocs.doc memoize.doc modules.doc
numbers.doc objprop.doc options.doc pairs.doc ports.doc print.doc
procprop.doc procs.doc promises.doc r6rs-ports.doc random.doc
rdelim.doc read.doc rw.doc scmsigs.doc script.doc simpos.doc smob.doc
sort.doc srcprop.doc srfi-1.doc srfi-4.doc srfi-13.doc srfi-14.doc
srfi-60.doc stackchk.doc stacks.doc stime.doc strings.doc strorder.doc
strports.doc struct.doc symbols.doc syntax.doc threads.doc throw.doc
unicode.doc uniform.doc values.doc variable.doc vectors.doc
version.doc vports.doc weak-set.doc weak-table.doc weak-vector.doc
dynl.doc posix.doc net_db.doc socket.doc regex-posix.doc |
GUILE_AUTO_COMPILE=0 ../meta/build-env guild
snarf-check-and-output-texi          > guile-procedures.texi || { rm
guile-procedures.texi; false; }
allocating JIT code buffer failed: Permission denied
jit.c:5804: fatal: assertion failed
/bin/sh: line 1: 58915 Broken pipe: 13         cat alist.doc
array-handle.doc array-map.doc arrays.doc async.doc atomic.doc
backtrace.doc boolean.doc bitvectors.doc bytevectors.doc chars.doc
control.doc continuations.doc debug.doc deprecated.doc deprecation.doc
dynl.doc dynwind.doc eq.doc error.doc eval.doc evalext.doc
exceptions.doc expand.doc extensions.doc fdes-finalizers.doc
feature.doc filesys.doc fluids.doc foreign.doc fports.doc
gc-malloc.doc gc.doc gettext.doc generalized-arrays.doc
generalized-vectors.doc goops.doc gsubr.doc guardians.doc hash.doc
hashtab.doc hooks.doc i18n.doc init.doc ioext.doc keywords.doc
list.doc load.doc macros.doc mallocs.doc memoize.doc modules.doc
numbers.doc objprop.doc options.doc pairs.doc ports.doc print.doc
procprop.doc procs.doc promises.doc r6rs-ports.doc random.doc
rdelim.doc read.doc rw.doc scmsigs.doc script.doc simpos.doc smob.doc
sort.doc srcprop.doc srfi-1.doc srfi-4.doc srfi-13.doc srfi-14.doc
srfi-60.doc stackchk.doc stacks.doc stime.doc strings.doc strorder.doc
strports.doc struct.doc symbols.doc syntax.doc threads.doc throw.doc
unicode.doc uniform.doc values.doc variable.doc vectors.doc
version.doc vports.doc weak-set.doc weak-table.doc weak-vector.doc
dynl.doc posix.doc net_db.doc socket.doc regex-posix.doc
     58916 Abort trap: 6           | GUILE_AUTO_COMPILE=0
../meta/build-env guild snarf-check-and-output-texi >
guile-procedures.texi
gmake[3]: *** [guile-procedures.texi] Error 1
[guile3-config.log.zip (application/zip, attachment)]

Information forwarded to bug-guile <at> gnu.org:
bug#47429; Package guile. (Fri, 26 Mar 2021 23:28:01 GMT) Full text and rfc822 format available.

Message #8 received at 47429 <at> debbugs.gnu.org (full text, mbox):

From: Jeffrey Walton <noloader <at> gmail.com>
To: 47429 <at> debbugs.gnu.org
Subject: Re 47429:allocating JIT code buffer failed: Permission denied
Date: Fri, 26 Mar 2021 19:27:18 -0400
I'm looking at OS X's man page on mmap. The EACCES does not seem to
fit one of the stated reasons in the man page. Also see
https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mmap.2.html.

I have two theories, both of which are guesses. Neither seems to be
very good. First, this may be related to W^X pages on OS X.

Second, the size is 0 but the wrong error code is returned. For the
second case, size=0 should result in EINVAL. I don't know what size is
so this is probably a bad guess.

I'm not sure how to get this under a debugger.

Here's a test of the first theory:

% cat mmap-test.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>

int main(int argc, char* argv[])
{
    size_t len = 10;
    int prot = PROT_EXEC | PROT_READ | PROT_WRITE;
    int flags = MAP_PRIVATE | MAP_ANONYMOUS;

    void *p = mmap (NULL, len, prot, flags, -1, 0);
    int err = errno;

    if (p) {
        printf("p is good\n");
        munmap(p, len);
    }
    else {
        printf("p is bad (%d)\n", err);
    }

    return 0;
}

% clang -Wall mmap-test.c -o mmap-test.exe
% ./mmap-test.exe
p is good

Here's a test of the second theory with len = 0:

% ./mmap-test.exe
p is good

I'm out of ideas...

=========================

This is the relevant part of libguile/jit.c:

  1330  static struct code_arena *
  1331  allocate_code_arena (size_t size, struct code_arena *prev)
  1332  {
  1333    struct code_arena *ret = malloc (sizeof (struct code_arena));
  1334
  1335    if (!ret) return NULL;
  1336
  1337    memset (ret, 0, sizeof (*ret));
  1338    ret->used = 0;
  1339    ret->size = size;
  1340    ret->prev = prev;
  1341    ret->base = mmap (NULL, ret->size,
  1342                      PROT_EXEC | PROT_READ | PROT_WRITE,
  1343                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  1344
  1345    if (ret->base == MAP_FAILED)
  1346      {
  1347        perror ("allocating JIT code buffer failed");
  1348        free (ret);
  1349        return NULL;
  1350      }
  1351
  1352    INFO ("allocated code arena, %p-%p\n", ret->base, ret->base
+ ret->size);
  1353
  1354    return ret;
  1355  }




Information forwarded to bug-guile <at> gnu.org:
bug#47429; Package guile. (Fri, 26 Mar 2021 23:35:01 GMT) Full text and rfc822 format available.

Message #11 received at 47429 <at> debbugs.gnu.org (full text, mbox):

From: Jeffrey Walton <noloader <at> gmail.com>
To: 47429 <at> debbugs.gnu.org
Subject: Re 47429:allocating JIT code buffer failed: Permission denied
Date: Fri, 26 Mar 2021 19:34:24 -0400
Dammit, check for the proper return value...

% cat mmap-test.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
int main(int argc, char* argv[])
{
    size_t len = 10;
    int prot = PROT_EXEC | PROT_READ | PROT_WRITE;
    int flags = MAP_PRIVATE | MAP_ANONYMOUS;

    void *p = mmap (NULL, len, prot, flags, -1, 0);
    int err = errno;

    if (p != (void*) -1) {
        printf("p is good\n");
        munmap(p, len);
    }
    else {
        printf("p is bad (%d)\n", err);
    }

    return 0;
}

% clang -Wall mmap-test.c -o mmap-test.exe
% ./mmap-test.exe
p is bad (13)

That is the permission denied.

Next, avoid W+X:

% cat mmap-test.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/mman.h>
int main(int argc, char* argv[])
{
    size_t len = 10;
    int prot = /*PROT_EXEC |*/ PROT_READ | PROT_WRITE;
    int flags = MAP_PRIVATE | MAP_ANONYMOUS;

    void *p = mmap (NULL, len, prot, flags, -1, 0);
    int err = errno;

    if (p != (void*) -1) {
        printf("p is good\n");
        munmap(p, len);
    }
    else {
        printf("p is bad (%d)\n", err);
    }

    return 0;
}

It looks like W^X is the culprit.

Jeff




Information forwarded to bug-guile <at> gnu.org:
bug#47429; Package guile. (Sat, 27 Mar 2021 01:30:02 GMT) Full text and rfc822 format available.

Message #14 received at 47429 <at> debbugs.gnu.org (full text, mbox):

From: Jeffrey Walton <noloader <at> gmail.com>
To: 47429 <at> debbugs.gnu.org
Subject: Re 47429:allocating JIT code buffer failed: Permission denied
Date: Fri, 26 Mar 2021 21:29:07 -0400
This looks like the Apple article of interest:
https://developer.apple.com/documentation/apple-silicon/porting-just-in-time-compilers-to-apple-silicon.

According to the article, the page should be mapped with MAP_JIT.
Before instructions are written, pthread_jit_write_protect_np should
be called. After writing the jitted code, call
pthread_jit_write_protect_np again and call sys_icache_invalidate.

It looks like the OpenJDK folks are also experiencing similar issues.

Jeff




Information forwarded to bug-guile <at> gnu.org:
bug#47429; Package guile. (Sat, 27 Mar 2021 02:40:02 GMT) Full text and rfc822 format available.

Message #17 received at 47429 <at> debbugs.gnu.org (full text, mbox):

From: Jeffrey Walton <noloader <at> gmail.com>
To: 47429 <at> debbugs.gnu.org
Subject: Re 47429:allocating JIT code buffer failed: Permission denied
Date: Fri, 26 Mar 2021 22:39:19 -0400
The GUILE_ENABLE_JIT m4 macro should _not_enable JIT on the Apple
silicon. That's going to take a real port.

This may help in detecting the M1 as long as build==host.

    apple_silicon=`sysctl machdep.cpu.brand_string 2>/dev/null | grep
-i -c "Apple M1"`

If a cross-compile is happening, then TARGET_OSX and MAP_JIT macros may help.

Jeff




This bug report was last modified 4 years and 79 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.