add `configure' test for mmap() and mprotect()

Use the test to enable execute permission on memory that is allocated
for code, including FFI callbacks.
This commit is contained in:
Matthew Flatt 2012-12-31 08:24:13 -06:00
parent a948f1b40d
commit ba973a317f
4 changed files with 117 additions and 10 deletions

74
src/configure vendored
View File

@ -3938,6 +3938,13 @@ if test "${enable_shared}" = "yes" ; then
LIBRACKET_DEP="${LIBRACKET_DEP} libmzgc.la"
fi
if test "${enable_foreign}" = "yes" ; then
check_for_mprotect=yes
fi
if test "${enable_jit}" = "yes" ; then
check_for_mprotect=yes
fi
############## platform tests ################
# for flags we don't want to use in config tests:
@ -4047,6 +4054,7 @@ case "$host_os" in
EXE_SUFFIX=".exe"
COLLECTS_PATH="collects"
skip_iconv_check=yes
check_for_mprotect=no
cat >>confdefs.h <<\_ACEOF
#define HAVE_STDINT_H 1
@ -5531,6 +5539,72 @@ echo "${ECHO_T}$have_libffi" >&6; }
fi
fi
if test "${check_for_mprotect}" = "yes" ; then
msg="for mmap and mprotect"
{ echo "$as_me:$LINENO: checking $msg" >&5
echo $ECHO_N "checking $msg... $ECHO_C" >&6; }
if test "$cross_compiling" = yes; then
use_mprotect=no
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <sys/mman.h>
#include <fcntl.h>
int main() {
void *p;
p = mmap(0, 2 << 16, PROT_READ | PROT_WRITE, MAP_PRIVATE, open("/dev/zero", O_RDWR), 0);
mprotect(p, 2 << 16, PROT_READ | PROT_WRITE | PROT_EXEC);
return 0;
}
_ACEOF
rm -f conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
{ (case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_try") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
use_mprotect=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
use_mprotect=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
{ echo "$as_me:$LINENO: result: $use_mprotect" >&5
echo "${ECHO_T}$use_mprotect" >&6; }
if test "${use_mprotect}" = "yes" ; then
cat >>confdefs.h <<\_ACEOF
#define HAVE_MMAP_MPROTECT 1
_ACEOF
fi
fi
if test "${enable_backtrace}" = "yes" ; then
GC2OPTIONS="$GC2OPTIONS -DMZ_GC_BACKTRACE"
fi

View File

@ -469,6 +469,13 @@ if test "${enable_shared}" = "yes" ; then
LIBRACKET_DEP="${LIBRACKET_DEP} libmzgc.la"
fi
if test "${enable_foreign}" = "yes" ; then
check_for_mprotect=yes
fi
if test "${enable_jit}" = "yes" ; then
check_for_mprotect=yes
fi
############## platform tests ################
# for flags we don't want to use in config tests:
@ -578,6 +585,7 @@ case "$host_os" in
EXE_SUFFIX=".exe"
COLLECTS_PATH="collects"
skip_iconv_check=yes
check_for_mprotect=no
AC_DEFINE(HAVE_STDINT_H,1,[Have stdint.h])
if `which ${host}-windres > /dev/null` ; then
WINDRES="${host}-windres"
@ -976,6 +984,24 @@ if test "${enable_libffi}" = "yes" ; then
fi
fi
if test "${check_for_mprotect}" = "yes" ; then
[ msg="for mmap and mprotect" ]
AC_MSG_CHECKING($msg)
AC_TRY_RUN(
[ #include <sys/mman.h> ]
[ #include <fcntl.h> ]
int main() {
void *p;
p = mmap(0, 2 << 16, PROT_READ | PROT_WRITE, MAP_PRIVATE, open("/dev/zero", O_RDWR), 0);
mprotect(p, 2 << 16, PROT_READ | PROT_WRITE | PROT_EXEC);
return 0;
}, use_mprotect=yes, use_mprotect=no, use_mprotect=no)
AC_MSG_RESULT($use_mprotect)
if test "${use_mprotect}" = "yes" ; then
AC_DEFINE(HAVE_MMAP_MPROTECT,1,[Have mmap and mprotect])
fi
fi
if test "${enable_backtrace}" = "yes" ; then
GC2OPTIONS="$GC2OPTIONS -DMZ_GC_BACKTRACE"
fi

View File

@ -61,6 +61,9 @@ typedef unsigned long uintptr_t;
#undef HAVE_EPOLL_SYSCALL
#undef HAVE_KQUEUE_SYSCALL
/* When mmap() and mprotect() are available: */
#undef HAVE_MMAP_MPROTECT
/* Enable futures: */
#undef MZ_USE_FUTURES

View File

@ -39,7 +39,11 @@
# define MALLOC malloc
#endif
#ifdef MZ_JIT_USE_MPROTECT
#if defined(MZ_JIT_USE_MPROTECT) || defined(HAVE_MMAP_MPROTECT)
# define MZ_CODE_ALLOC_USE_MPROTECT
#endif
#ifdef MZ_CODE_ALLOC_USE_MPROTECT
# include <unistd.h>
# include <sys/mman.h>
# ifndef MAP_ANON
@ -851,14 +855,14 @@ THREAD_LOCAL_DECL(static void *code_allocation_page_list);
THREAD_LOCAL_DECL(intptr_t scheme_code_page_total);
#if defined(MZ_JIT_USE_MPROTECT) && !defined(MAP_ANON)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) && !defined(MAP_ANON)
static int fd, fd_created;
#endif
#define LOG_CODE_MALLOC(lvl, s) /* if (lvl > 1) s */
#define CODE_PAGE_OF(p) ((void *)(((uintptr_t)p) & ~(page_size - 1)))
#if defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
struct free_list_entry {
intptr_t size; /* size of elements in this bucket */
@ -1030,7 +1034,7 @@ static intptr_t free_list_find_bucket(intptr_t size)
void *scheme_malloc_code(intptr_t size)
{
#if defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
intptr_t size2, bucket, sz, page_size;
void *p, *pg, *prev;
@ -1109,7 +1113,7 @@ void *scheme_malloc_permanent_code(intptr_t size)
/* allocate code that will never be freed and that can be used
in multiple places */
{
#if defined(MZ_USE_PLACES) && (defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC))
#if defined(MZ_USE_PLACES) && (defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC))
void *p;
intptr_t page_size;
@ -1148,7 +1152,7 @@ void *scheme_malloc_permanent_code(intptr_t size)
void scheme_free_code(void *p)
{
#if defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
intptr_t size, size2, bucket, page_size;
int per_page, n;
void *prev;
@ -1234,7 +1238,7 @@ void scheme_free_code(void *p)
void scheme_free_all_code(void)
{
#if defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
void *p, *next;
intptr_t page_size;
@ -1260,7 +1264,7 @@ void scheme_free_all_code(void)
currently takes advantage of that combination, so we support it
with scheme_malloc_gcable_code() --- but only in CGC mode. */
#if defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
static uintptr_t jit_prev_page = 0, jit_prev_length = 0;
#endif
@ -1269,7 +1273,7 @@ void *scheme_malloc_gcable_code(intptr_t size)
void *p;
p = scheme_malloc(size);
#if defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
{
/* [This chunk of code moved from our copy of GNU lightning to here.] */
uintptr_t page, length, page_size;
@ -1324,7 +1328,7 @@ void *scheme_malloc_gcable_code(intptr_t size)
void scheme_notify_code_gc()
{
#if defined(MZ_JIT_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
#if defined(MZ_CODE_ALLOC_USE_MPROTECT) || defined(MZ_JIT_USE_WINDOWS_VIRTUAL_ALLOC)
jit_prev_page = 0;
jit_prev_length = 0;
#endif