[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
jit/cache tests: Avoid test failure on CentOS, *BSD, macOS
From: |
Bruno Haible |
Subject: |
jit/cache tests: Avoid test failure on CentOS, *BSD, macOS |
Date: |
Mon, 08 Jan 2024 17:25:24 +0100 |
Testing the jit/cache module on various x86_64 platforms, I see test failures:
- On CentOS. Here the problem is that pagealign_alloc returns a piece of memory
with PROT_READ | PROT_WRITE access. The mprotect that wants to install
a PROT_EXEC access then fails. The solution is to give the right protection
flags to mmap(), and not invoke mprotect().
- On *BSD and macOS. Here, the solution that works for CentOS does not work:
mmap (..., PROT_READ | PROT_WRITE | PROT_EXEC, ...) fails, due to security
reasons. The solution is to use two different mmap() invocations for the
same memory.
Also, some of the #if conditions were incorrect:
- '#if defined __hppa__' is needed instead of '#if __hppa__'.
- Allow for __hppa__ to be set in __hppa64__ mode, and allow for __ia64__
to be set in 32-bit ia64 mode.
2024-01-08 Bruno Haible <bruno@clisp.org>
jit/cache tests: Avoid test failure on CentOS, *BSD, macOS.
* tests/jit/test-cache.c: Include <fcntl.h>, <stdio.h>, <stdlib.h>.
Don't include pagealign_alloc.h. Include clean-temp-simple.h. Don't test
HAVE_MPROTECT.
(struct func): Fix #if conditions.
(main): Don't invoke pagealign_xalloc and mprotect. Instead, invoke
mmap,
using a temporary file if needed.
* modules/jit/cache-tests (Files): Add m4/mmap-anon.m4.
(Depends-on): Add clean-temp-simple. Remove pagealign_alloc.
(configure.ac): Invoke gl_FUNC_MMAP_ANON. Don't test for mprotect.
diff --git a/modules/jit/cache-tests b/modules/jit/cache-tests
index 6a713f8bb9..e4229476c8 100644
--- a/modules/jit/cache-tests
+++ b/modules/jit/cache-tests
@@ -1,19 +1,20 @@
Files:
tests/jit/test-cache.c
tests/macros.h
+m4/mmap-anon.m4
Status:
unportable-test
Depends-on:
+clean-temp-simple
getpagesize
host-cpu-c-abi
-pagealign_alloc
stdint
configure.ac:
AC_CHECK_HEADERS_ONCE([sys/mman.h])
-AC_CHECK_FUNCS_ONCE([mprotect])
+gl_FUNC_MMAP_ANON
Makefile.am:
TESTS += test-cache
diff --git a/tests/jit/test-cache.c b/tests/jit/test-cache.c
index 8ced2e819c..35d63b7842 100644
--- a/tests/jit/test-cache.c
+++ b/tests/jit/test-cache.c
@@ -1,6 +1,6 @@
/* Test clear_cache.
- Copyright 2023-2024 Free Software Foundation, Inc.
+ Copyright 2020-2024 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -17,16 +17,25 @@
#include <config.h>
+/* Specification. */
#include <jit/cache.h>
-#include <pagealign_alloc.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#if HAVE_SYS_MMAN_H && HAVE_MPROTECT
+#if HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
+#if defined __APPLE__ && defined __MACH__ /* only needed on macOS */
+# define KEEP_TEMP_FILE_VISIBLE
+/* Support for temporary files that are cleaned up automatically. */
+# include "clean-temp-simple.h"
+#endif
+
#include "macros.h"
/* On most platforms, function pointers are just a pointer to the
@@ -43,33 +52,37 @@ struct func
void *static_chain;
};
#elif defined __ia64__
+# if defined __ia64_ilp32__
struct func
{
void *code_address;
+ void *unused1;
void *global_pointer;
+ void *unused2;
};
-#elif defined __ia64_ilp32__
+# else
struct func
{
void *code_address;
- void *unused1;
void *global_pointer;
- void *unused2;
};
-#elif __hppa__
+# endif
+#elif defined __hppa__
+# if defined __hppa64__
struct func
{
+ void *some_other_code_address;
+ void *some_other_pic_base;
void *code_address;
void *pic_base;
};
-#elif __hppa64__
+# else
struct func
{
- void *some_other_code_address;
- void *some_other_pic_base;
void *code_address;
void *pic_base;
};
+# endif
#else
# undef CODE
# define CODE(fn) ((*(void **) (&fn)))
@@ -94,27 +107,81 @@ return2 (void)
int
main ()
{
-#if !(HAVE_SYS_MMAN_H && HAVE_MPROTECT)
+#if !HAVE_SYS_MMAN_H
return 77;
#else
int const pagesize = getpagesize ();
- unsigned char *start = pagealign_xalloc (pagesize);
- unsigned char *end = start + pagesize;
-
- /* We have to call `mprotect' before the tests because on some
- platforms `mprotect' invalidates the caches. */
- mprotect (start, end - start, PROT_READ | PROT_WRITE | PROT_EXEC);
+ int const mapping_size = 1 * pagesize;
+ /* Bounds of an executable memory region. */
+ char *start;
+ char *end;
+ /* Start of a writable memory region. */
+ char *start_rw;
+
+ /* Initialization. */
+ {
+# ifdef HAVE_MAP_ANONYMOUS
+ int flags = MAP_ANONYMOUS | MAP_PRIVATE;
+ int fd = -1;
+# else
+ int flags = MAP_FILE | MAP_PRIVATE;
+ int fd = open ("/dev/zero", O_RDONLY | O_CLOEXEC, 0666);
+ if (fd < 0)
+ return 1;
+# endif
+ start = mmap (NULL, mapping_size, PROT_READ | PROT_WRITE | PROT_EXEC,
+ flags, fd, 0);
+ if (start != (char *) (-1))
+ {
+ /* A platform that allows a mmap'ed memory region to be simultaneously
+ writable and executable. */
+ start_rw = start;
+ }
+ else
+ {
+ /* A platform which requires the writable mapping and the executable
+ mapping to be separate: macOS, FreeBSD, NetBSD, OpenBSD. */
+ fprintf (stderr, "simple mmap failed, using separate mappings\n");
+ char filename[100];
+ sprintf (filename,
+ "%s/gnulib-test-cache-%u-%d-%ld",
+ "/tmp", (unsigned int) getuid (), (int) getpid (), random ());
+# ifdef KEEP_TEMP_FILE_VISIBLE
+ if (register_temporary_file (filename) < 0)
+ return 2;
+# endif
+ fd = open (filename, O_CREAT | O_RDWR | O_TRUNC, 0700);
+ if (fd < 0)
+ return 3;
+# ifndef KEEP_TEMP_FILE_VISIBLE
+ /* Remove the file from the file system as soon as possible, to make
+ sure there is no leftover after this process terminates or crashes.
+ On macOS 11.2, this does not work: It would make the mmap call
below,
+ with arguments PROT_READ|PROT_EXEC and MAP_SHARED, fail. */
+ unlink (filename);
+# endif
+ if (ftruncate (fd, mapping_size) < 0)
+ return 4;
+ start = mmap (NULL, mapping_size, PROT_READ | PROT_EXEC, MAP_SHARED,
+ fd, 0);
+ start_rw = mmap (NULL, mapping_size, PROT_READ | PROT_WRITE,
MAP_SHARED,
+ fd, 0);
+ if (start == (char *) (-1) || start_rw == (char *) (-1))
+ return 5;
+ }
+ end = start + mapping_size;
+ }
int (*f) (void) = return1;
CODE (f) = start;
/* We assume that the code is not longer than 64 bytes and that we
can access the full 64 bytes for reading. */
- memcpy (start, return1, 64);
+ memcpy (start_rw, return1, 64);
clear_cache (start, end);
ASSERT (f () == 1);
- memcpy (start, return2, 64);
+ memcpy (start_rw, return2, 64);
clear_cache (start, end);
ASSERT (f () == 2);
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- jit/cache tests: Avoid test failure on CentOS, *BSD, macOS,
Bruno Haible <=