1
/* -----------------------------------------------------------------------
2
closures.c - Copyright (c) 2007, 2009, 2010 Red Hat, Inc.
3
Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc
4
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
6
Code to allocate and deallocate memory for closures.
8
Permission is hereby granted, free of charge, to any person obtaining
9
a copy of this software and associated documentation files (the
10
``Software''), to deal in the Software without restriction, including
11
without limitation the rights to use, copy, modify, merge, publish,
12
distribute, sublicense, and/or sell copies of the Software, and to
13
permit persons to whom the Software is furnished to do so, subject to
14
the following conditions:
16
The above copyright notice and this permission notice shall be included
17
in all copies or substantial portions of the Software.
19
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26
DEALINGS IN THE SOFTWARE.
27
----------------------------------------------------------------------- */
29
#if defined __linux__ && !defined _GNU_SOURCE
34
#include <ffi_common.h>
36
#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
38
/* This macro indicates it may be forbidden to map anonymous memory
39
with both write and execute permission. Code compiled when this
40
option is defined will attempt to map such pages once, but if it
41
fails, it falls back to creating a temporary file in a writable and
42
executable filesystem and mapping pages from it into separate
43
locations in the virtual memory space, one location writable and
44
another executable. */
45
# define FFI_MMAP_EXEC_WRIT 1
46
# define HAVE_MNTENT 1
48
# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)
49
/* Windows systems may have Data Execution Protection (DEP) enabled,
50
which requires the use of VirtualMalloc/VirtualFree to alloc/free
52
# define FFI_MMAP_EXEC_WRIT 1
56
#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
58
/* When defined to 1 check for SELinux and if SELinux is active,
59
don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
60
might cause audit messages. */
61
# define FFI_MMAP_EXEC_SELINUX 1
67
# if FFI_EXEC_TRAMPOLINE_TABLE
69
// Per-target implementation; It's unclear what can reasonable be shared between two OS/architecture implementations.
71
# elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
74
#define USE_DL_PREFIX 1
76
#ifndef USE_BUILTIN_FFS
77
#define USE_BUILTIN_FFS 1
81
/* We need to use mmap, not sbrk. */
82
#define HAVE_MORECORE 0
84
/* We could, in theory, support mremap, but it wouldn't buy us anything. */
87
/* We have no use for this, so save some code and data. */
90
/* We need all allocations to be in regular segments, otherwise we
91
lose track of the corresponding code address. */
92
#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
94
/* Don't allocate more than a page unless needed. */
95
#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
98
/* Don't release single pages, to avoid a worst-case scenario of
99
continuously allocating and releasing single pages, but release
100
pairs of pages, which should do just as well given that allocations
101
are likely to be small. */
102
#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
105
#include <sys/types.h>
106
#include <sys/stat.h>
114
#if !defined(X86_WIN32) && !defined(X86_WIN64)
117
#endif /* HAVE_MNTENT */
118
#include <sys/param.h>
121
/* We don't want sys/mman.h to be included after we redefine mmap and
123
#include <sys/mman.h>
124
#define LACKS_SYS_MMAN_H 1
126
#if FFI_MMAP_EXEC_SELINUX
127
#include <sys/statfs.h>
130
static int selinux_enabled = -1;
133
selinux_enabled_check (void)
140
if (statfs ("/selinux", &sfs) >= 0
141
&& (unsigned int) sfs.f_type == 0xf97cff8cU)
143
f = fopen ("/proc/mounts", "r");
146
while (getline (&buf, &len, f) >= 0)
148
char *p = strchr (buf, ' ');
151
p = strchr (p + 1, ' ');
154
if (strncmp (p + 1, "selinuxfs ", 10) == 0)
166
#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
167
: (selinux_enabled = selinux_enabled_check ()))
171
#define is_selinux_enabled() 0
173
#endif /* !FFI_MMAP_EXEC_SELINUX */
175
/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */
176
#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
179
static int emutramp_enabled = -1;
182
emutramp_enabled_check (void)
184
if (getenv ("FFI_DISABLE_EMUTRAMP") == NULL)
190
#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
191
: (emutramp_enabled = emutramp_enabled_check ()))
192
#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
194
#elif defined (__CYGWIN__) || defined(__INTERIX)
196
#include <sys/mman.h>
198
/* Cygwin is Linux-like, but not quite that Linux-like. */
199
#define is_selinux_enabled() 0
201
#endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
203
#ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
204
#define is_emutramp_enabled() 0
205
#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
207
/* Declare all functions defined in dlmalloc.c as static. */
208
static void *dlmalloc(size_t);
209
static void dlfree(void*);
210
static void *dlcalloc(size_t, size_t) MAYBE_UNUSED;
211
static void *dlrealloc(void *, size_t) MAYBE_UNUSED;
212
static void *dlmemalign(size_t, size_t) MAYBE_UNUSED;
213
static void *dlvalloc(size_t) MAYBE_UNUSED;
214
static int dlmallopt(int, int) MAYBE_UNUSED;
215
static size_t dlmalloc_footprint(void) MAYBE_UNUSED;
216
static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED;
217
static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED;
218
static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED;
219
static void *dlpvalloc(size_t) MAYBE_UNUSED;
220
static int dlmalloc_trim(size_t) MAYBE_UNUSED;
221
static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
222
static void dlmalloc_stats(void) MAYBE_UNUSED;
224
#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
225
/* Use these for mmap and munmap within dlmalloc.c. */
226
static void *dlmmap(void *, size_t, int, int, int, off_t);
227
static int dlmunmap(void *, size_t);
228
#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
231
#define munmap dlmunmap
233
#include "dlmalloc.c"
238
#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
240
/* A mutex used to synchronize access to *exec* variables in this file. */
241
static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
243
/* A file descriptor of a temporary file from which we'll map
245
static int execfd = -1;
247
/* The amount of space already allocated from the temporary file. */
248
static size_t execsize = 0;
250
/* Open a temporary file name, and immediately unlink it. */
252
open_temp_exec_file_name (char *name)
254
int fd = mkstemp (name);
262
/* Open a temporary file in the named directory. */
264
open_temp_exec_file_dir (const char *dir)
266
static const char suffix[] = "/ffiXXXXXX";
267
int lendir = strlen (dir);
268
char *tempname = __builtin_alloca (lendir + sizeof (suffix));
273
memcpy (tempname, dir, lendir);
274
memcpy (tempname + lendir, suffix, sizeof (suffix));
276
return open_temp_exec_file_name (tempname);
279
/* Open a temporary file in the directory in the named environment
282
open_temp_exec_file_env (const char *envvar)
284
const char *value = getenv (envvar);
289
return open_temp_exec_file_dir (value);
293
/* Open a temporary file in an executable and writable mount point
294
listed in the mounts file. Subsequent calls with the same mounts
295
keep searching for mount points in the same file. Providing NULL
296
as the mounts file closes the file. */
298
open_temp_exec_file_mnt (const char *mounts)
300
static const char *last_mounts;
301
static FILE *last_mntent;
303
if (mounts != last_mounts)
306
endmntent (last_mntent);
308
last_mounts = mounts;
311
last_mntent = setmntent (mounts, "r");
323
char buf[MAXPATHLEN * 3];
325
if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)) == NULL)
328
if (hasmntopt (&mnt, "ro")
329
|| hasmntopt (&mnt, "noexec")
330
|| access (mnt.mnt_dir, W_OK))
333
fd = open_temp_exec_file_dir (mnt.mnt_dir);
339
#endif /* HAVE_MNTENT */
341
/* Instructions to look for a location to hold a temporary file that
342
can be mapped in for execution. */
345
int (*func)(const char *);
348
} open_temp_exec_file_opts[] = {
349
{ open_temp_exec_file_env, "TMPDIR", 0 },
350
{ open_temp_exec_file_dir, "/tmp", 0 },
351
{ open_temp_exec_file_dir, "/var/tmp", 0 },
352
{ open_temp_exec_file_dir, "/dev/shm", 0 },
353
{ open_temp_exec_file_env, "HOME", 0 },
355
{ open_temp_exec_file_mnt, "/etc/mtab", 1 },
356
{ open_temp_exec_file_mnt, "/proc/mounts", 1 },
357
#endif /* HAVE_MNTENT */
360
/* Current index into open_temp_exec_file_opts. */
361
static int open_temp_exec_file_opts_idx = 0;
363
/* Reset a current multi-call func, then advances to the next entry.
364
If we're at the last, go back to the first and return nonzero,
365
otherwise return zero. */
367
open_temp_exec_file_opts_next (void)
369
if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
370
open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
372
open_temp_exec_file_opts_idx++;
373
if (open_temp_exec_file_opts_idx
374
== (sizeof (open_temp_exec_file_opts)
375
/ sizeof (*open_temp_exec_file_opts)))
377
open_temp_exec_file_opts_idx = 0;
384
/* Return a file descriptor of a temporary zero-sized file in a
385
writable and exexutable filesystem. */
387
open_temp_exec_file (void)
393
fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
394
(open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
396
if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
399
if (open_temp_exec_file_opts_next ())
408
/* Map in a chunk of memory from the temporary exec file into separate
409
locations in the virtual memory address space, one writable and one
410
executable. Returns the address of the writable portion, after
411
storing an offset to the corresponding executable portion at the
412
last word of the requested chunk. */
414
dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
420
open_temp_exec_file_opts_idx = 0;
422
execfd = open_temp_exec_file ();
429
if (ftruncate (execfd, offset + length))
432
flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
435
ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
436
flags, execfd, offset);
444
ftruncate (execfd, offset);
448
&& open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
449
open_temp_exec_file_opts_next ();
451
start = mmap (start, length, prot, flags, execfd, offset);
455
munmap (ptr, length);
456
ftruncate (execfd, offset);
460
mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
467
/* Map in a writable and executable chunk of memory if possible.
468
Failing that, fall back to dlmmap_locked. */
470
dlmmap (void *start, size_t length, int prot,
471
int flags, int fd, off_t offset)
475
assert (start == NULL && length % malloc_getpagesize == 0
476
&& prot == (PROT_READ | PROT_WRITE)
477
&& flags == (MAP_PRIVATE | MAP_ANONYMOUS)
478
&& fd == -1 && offset == 0);
481
printf ("mapping in %zi\n", length);
484
if (execfd == -1 && is_emutramp_enabled ())
486
ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
490
if (execfd == -1 && !is_selinux_enabled ())
492
ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
494
if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
495
/* Cool, no need to mess with separate segments. */
498
/* If MREMAP_DUP is ever introduced and implemented, try mmap
499
with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
500
MREMAP_DUP and prot at this point. */
503
if (execsize == 0 || execfd == -1)
505
pthread_mutex_lock (&open_temp_exec_file_mutex);
506
ptr = dlmmap_locked (start, length, prot, flags, offset);
507
pthread_mutex_unlock (&open_temp_exec_file_mutex);
512
return dlmmap_locked (start, length, prot, flags, offset);
515
/* Release memory at the given address, as well as the corresponding
516
executable page if it's separate. */
518
dlmunmap (void *start, size_t length)
520
/* We don't bother decreasing execsize or truncating the file, since
521
we can't quite tell whether we're unmapping the end of the file.
522
We don't expect frequent deallocation anyway. If we did, we
523
could locate pages in the file by writing to the pages being
524
deallocated and checking that the file contents change.
526
msegmentptr seg = segment_holding (gm, start);
530
printf ("unmapping %zi\n", length);
533
if (seg && (code = add_segment_exec_offset (start, seg)) != start)
535
int ret = munmap (code, length);
540
return munmap (start, length);
543
#if FFI_CLOSURE_FREE_CODE
544
/* Return segment holding given code address. */
546
segment_holding_code (mstate m, char* addr)
548
msegmentptr sp = &m->seg;
550
if (addr >= add_segment_exec_offset (sp->base, sp)
551
&& addr < add_segment_exec_offset (sp->base, sp) + sp->size)
553
if ((sp = sp->next) == 0)
559
#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
561
/* Allocate a chunk of memory with the given size. Returns a pointer
562
to the writable address, and sets *CODE to the executable
563
corresponding virtual address. */
565
ffi_closure_alloc (size_t size, void **code)
572
ptr = dlmalloc (size);
576
msegmentptr seg = segment_holding (gm, ptr);
578
*code = add_segment_exec_offset (ptr, seg);
584
/* Release a chunk of memory allocated with ffi_closure_alloc. If
585
FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
586
writable or the executable address given. Otherwise, only the
587
writable address can be provided here. */
589
ffi_closure_free (void *ptr)
591
#if FFI_CLOSURE_FREE_CODE
592
msegmentptr seg = segment_holding_code (gm, ptr);
595
ptr = sub_segment_exec_offset (ptr, seg);
603
/* Do some internal sanity testing to make sure allocation and
604
deallocation of pages are working as intended. */
608
#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
609
#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
610
GET (0, malloc_getpagesize / 2);
611
GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
613
GET (1, 2 * malloc_getpagesize);
614
GET (2, malloc_getpagesize / 2);
620
#endif /* FFI_CLOSURE_TEST */
621
# else /* ! FFI_MMAP_EXEC_WRIT */
623
/* On many systems, memory returned by malloc is writable and
624
executable, so just use it. */
629
ffi_closure_alloc (size_t size, void **code)
634
return *code = malloc (size);
638
ffi_closure_free (void *ptr)
643
# endif /* ! FFI_MMAP_EXEC_WRIT */
644
#endif /* FFI_CLOSURES */