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
37 # if __gnu_linux__ && !defined(__ANDROID__)
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)
188 f
= fopen ("/proc/self/status", "r");
193 while (getline (&buf
, &len
, f
) != -1)
194 if (!strncmp (buf
, "PaX:", 4))
197 if (sscanf (buf
, "%*s %*c%c", &emutramp
) == 1)
198 ret
= (emutramp
== 'E');
206 #define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
207 : (emutramp_enabled = emutramp_enabled_check ()))
208 #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
210 #elif defined (__CYGWIN__) || defined(__INTERIX)
212 #include <sys/mman.h>
214 /* Cygwin is Linux-like, but not quite that Linux-like. */
215 #define is_selinux_enabled() 0
217 #endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
219 #ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
220 #define is_emutramp_enabled() 0
221 #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
223 /* Declare all functions defined in dlmalloc.c as static. */
224 static void *dlmalloc(size_t);
225 static void dlfree(void*);
226 static void *dlcalloc(size_t, size_t) MAYBE_UNUSED
;
227 static void *dlrealloc(void *, size_t) MAYBE_UNUSED
;
228 static void *dlmemalign(size_t, size_t) MAYBE_UNUSED
;
229 static void *dlvalloc(size_t) MAYBE_UNUSED
;
230 static int dlmallopt(int, int) MAYBE_UNUSED
;
231 static size_t dlmalloc_footprint(void) MAYBE_UNUSED
;
232 static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED
;
233 static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED
;
234 static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED
;
235 static void *dlpvalloc(size_t) MAYBE_UNUSED
;
236 static int dlmalloc_trim(size_t) MAYBE_UNUSED
;
237 static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED
;
238 static void dlmalloc_stats(void) MAYBE_UNUSED
;
240 #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
241 /* Use these for mmap and munmap within dlmalloc.c. */
242 static void *dlmmap(void *, size_t, int, int, int, off_t
);
243 static int dlmunmap(void *, size_t);
244 #endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
247 #define munmap dlmunmap
249 #include "dlmalloc.c"
254 #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
256 /* A mutex used to synchronize access to *exec* variables in this file. */
257 static pthread_mutex_t open_temp_exec_file_mutex
= PTHREAD_MUTEX_INITIALIZER
;
259 /* A file descriptor of a temporary file from which we'll map
261 static int execfd
= -1;
263 /* The amount of space already allocated from the temporary file. */
264 static size_t execsize
= 0;
266 /* Open a temporary file name, and immediately unlink it. */
268 open_temp_exec_file_name (char *name
, int flags
)
273 fd
= mkostemp (name
, flags
);
284 /* Open a temporary file in the named directory. */
286 open_temp_exec_file_dir (const char *dir
)
288 static const char suffix
[] = "/ffiXXXXXX";
302 fd
= open (dir
, flags
| O_RDWR
| O_EXCL
| O_TMPFILE
, 0700);
303 /* If the running system does not support the O_TMPFILE flag then retry without it. */
304 if (fd
!= -1 || (errno
!= EINVAL
&& errno
!= EISDIR
&& errno
!= EOPNOTSUPP
)) {
311 lendir
= strlen (dir
);
312 tempname
= __builtin_alloca (lendir
+ sizeof (suffix
));
317 memcpy (tempname
, dir
, lendir
);
318 memcpy (tempname
+ lendir
, suffix
, sizeof (suffix
));
320 return open_temp_exec_file_name (tempname
, flags
);
323 /* Open a temporary file in the directory in the named environment
326 open_temp_exec_file_env (const char *envvar
)
328 const char *value
= getenv (envvar
);
333 return open_temp_exec_file_dir (value
);
337 /* Open a temporary file in an executable and writable mount point
338 listed in the mounts file. Subsequent calls with the same mounts
339 keep searching for mount points in the same file. Providing NULL
340 as the mounts file closes the file. */
342 open_temp_exec_file_mnt (const char *mounts
)
344 static const char *last_mounts
;
345 static FILE *last_mntent
;
347 if (mounts
!= last_mounts
)
350 endmntent (last_mntent
);
352 last_mounts
= mounts
;
355 last_mntent
= setmntent (mounts
, "r");
367 char buf
[MAXPATHLEN
* 3];
369 if (getmntent_r (last_mntent
, &mnt
, buf
, sizeof (buf
)) == NULL
)
372 if (hasmntopt (&mnt
, "ro")
373 || hasmntopt (&mnt
, "noexec")
374 || access (mnt
.mnt_dir
, W_OK
))
377 fd
= open_temp_exec_file_dir (mnt
.mnt_dir
);
383 #endif /* HAVE_MNTENT */
385 /* Instructions to look for a location to hold a temporary file that
386 can be mapped in for execution. */
389 int (*func
)(const char *);
392 } open_temp_exec_file_opts
[] = {
393 { open_temp_exec_file_env
, "TMPDIR", 0 },
394 { open_temp_exec_file_dir
, "/tmp", 0 },
395 { open_temp_exec_file_dir
, "/var/tmp", 0 },
396 { open_temp_exec_file_dir
, "/dev/shm", 0 },
397 { open_temp_exec_file_env
, "HOME", 0 },
399 { open_temp_exec_file_mnt
, "/etc/mtab", 1 },
400 { open_temp_exec_file_mnt
, "/proc/mounts", 1 },
401 #endif /* HAVE_MNTENT */
404 /* Current index into open_temp_exec_file_opts. */
405 static int open_temp_exec_file_opts_idx
= 0;
407 /* Reset a current multi-call func, then advances to the next entry.
408 If we're at the last, go back to the first and return nonzero,
409 otherwise return zero. */
411 open_temp_exec_file_opts_next (void)
413 if (open_temp_exec_file_opts
[open_temp_exec_file_opts_idx
].repeat
)
414 open_temp_exec_file_opts
[open_temp_exec_file_opts_idx
].func (NULL
);
416 open_temp_exec_file_opts_idx
++;
417 if (open_temp_exec_file_opts_idx
418 == (sizeof (open_temp_exec_file_opts
)
419 / sizeof (*open_temp_exec_file_opts
)))
421 open_temp_exec_file_opts_idx
= 0;
428 /* Return a file descriptor of a temporary zero-sized file in a
429 writable and executable filesystem. */
431 open_temp_exec_file (void)
437 fd
= open_temp_exec_file_opts
[open_temp_exec_file_opts_idx
].func
438 (open_temp_exec_file_opts
[open_temp_exec_file_opts_idx
].arg
);
440 if (!open_temp_exec_file_opts
[open_temp_exec_file_opts_idx
].repeat
443 if (open_temp_exec_file_opts_next ())
452 /* Map in a chunk of memory from the temporary exec file into separate
453 locations in the virtual memory address space, one writable and one
454 executable. Returns the address of the writable portion, after
455 storing an offset to the corresponding executable portion at the
456 last word of the requested chunk. */
458 dlmmap_locked (void *start
, size_t length
, int prot
, int flags
, off_t offset
)
464 open_temp_exec_file_opts_idx
= 0;
466 execfd
= open_temp_exec_file ();
473 if (ftruncate (execfd
, offset
+ length
))
476 flags
&= ~(MAP_PRIVATE
| MAP_ANONYMOUS
);
479 ptr
= mmap (NULL
, length
, (prot
& ~PROT_WRITE
) | PROT_EXEC
,
480 flags
, execfd
, offset
);
488 ftruncate (execfd
, offset
);
492 && open_temp_exec_file_opts
[open_temp_exec_file_opts_idx
].repeat
)
493 open_temp_exec_file_opts_next ();
495 start
= mmap (start
, length
, prot
, flags
, execfd
, offset
);
499 munmap (ptr
, length
);
500 ftruncate (execfd
, offset
);
504 mmap_exec_offset ((char *)start
, length
) = (char*)ptr
- (char*)start
;
511 /* Map in a writable and executable chunk of memory if possible.
512 Failing that, fall back to dlmmap_locked. */
514 dlmmap (void *start
, size_t length
, int prot
,
515 int flags
, int fd
, off_t offset
)
519 assert (start
== NULL
&& length
% malloc_getpagesize
== 0
520 && prot
== (PROT_READ
| PROT_WRITE
)
521 && flags
== (MAP_PRIVATE
| MAP_ANONYMOUS
)
522 && fd
== -1 && offset
== 0);
525 printf ("mapping in %zi\n", length
);
528 if (execfd
== -1 && is_emutramp_enabled ())
530 ptr
= mmap (start
, length
, prot
& ~PROT_EXEC
, flags
, fd
, offset
);
534 if (execfd
== -1 && !is_selinux_enabled ())
536 ptr
= mmap (start
, length
, prot
| PROT_EXEC
, flags
, fd
, offset
);
538 if (ptr
!= MFAIL
|| (errno
!= EPERM
&& errno
!= EACCES
))
539 /* Cool, no need to mess with separate segments. */
542 /* If MREMAP_DUP is ever introduced and implemented, try mmap
543 with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
544 MREMAP_DUP and prot at this point. */
547 if (execsize
== 0 || execfd
== -1)
549 pthread_mutex_lock (&open_temp_exec_file_mutex
);
550 ptr
= dlmmap_locked (start
, length
, prot
, flags
, offset
);
551 pthread_mutex_unlock (&open_temp_exec_file_mutex
);
556 return dlmmap_locked (start
, length
, prot
, flags
, offset
);
559 /* Release memory at the given address, as well as the corresponding
560 executable page if it's separate. */
562 dlmunmap (void *start
, size_t length
)
564 /* We don't bother decreasing execsize or truncating the file, since
565 we can't quite tell whether we're unmapping the end of the file.
566 We don't expect frequent deallocation anyway. If we did, we
567 could locate pages in the file by writing to the pages being
568 deallocated and checking that the file contents change.
570 msegmentptr seg
= segment_holding (gm
, start
);
574 printf ("unmapping %zi\n", length
);
577 if (seg
&& (code
= add_segment_exec_offset (start
, seg
)) != start
)
579 int ret
= munmap (code
, length
);
584 return munmap (start
, length
);
587 #if FFI_CLOSURE_FREE_CODE
588 /* Return segment holding given code address. */
590 segment_holding_code (mstate m
, char* addr
)
592 msegmentptr sp
= &m
->seg
;
594 if (addr
>= add_segment_exec_offset (sp
->base
, sp
)
595 && addr
< add_segment_exec_offset (sp
->base
, sp
) + sp
->size
)
597 if ((sp
= sp
->next
) == 0)
603 #endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
605 /* Allocate a chunk of memory with the given size. Returns a pointer
606 to the writable address, and sets *CODE to the executable
607 corresponding virtual address. */
609 ffi_closure_alloc (size_t size
, void **code
)
616 ptr
= dlmalloc (size
);
620 msegmentptr seg
= segment_holding (gm
, ptr
);
622 *code
= add_segment_exec_offset (ptr
, seg
);
628 /* Release a chunk of memory allocated with ffi_closure_alloc. If
629 FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
630 writable or the executable address given. Otherwise, only the
631 writable address can be provided here. */
633 ffi_closure_free (void *ptr
)
635 #if FFI_CLOSURE_FREE_CODE
636 msegmentptr seg
= segment_holding_code (gm
, ptr
);
639 ptr
= sub_segment_exec_offset (ptr
, seg
);
647 /* Do some internal sanity testing to make sure allocation and
648 deallocation of pages are working as intended. */
652 #define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
653 #define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
654 GET (0, malloc_getpagesize
/ 2);
655 GET (1, 2 * malloc_getpagesize
- 64 * sizeof (void*));
657 GET (1, 2 * malloc_getpagesize
);
658 GET (2, malloc_getpagesize
/ 2);
664 #endif /* FFI_CLOSURE_TEST */
665 # else /* ! FFI_MMAP_EXEC_WRIT */
667 /* On many systems, memory returned by malloc is writable and
668 executable, so just use it. */
673 ffi_closure_alloc (size_t size
, void **code
)
678 return *code
= malloc (size
);
682 ffi_closure_free (void *ptr
)
687 # endif /* ! FFI_MMAP_EXEC_WRIT */
688 #endif /* FFI_CLOSURES */