Merge trunk version 194962 into gupc branch.
[official-gcc.git] / libffi / src / closures.c
blobfecbc4ae2c9e7056e84c2561f6537e453ea7efc7
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
30 #define _GNU_SOURCE 1
31 #endif
33 #include <ffi.h>
34 #include <ffi_common.h>
36 #if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
37 # if __gnu_linux__
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
47 # endif
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
51 executable memory. */
52 # define FFI_MMAP_EXEC_WRIT 1
53 # endif
54 #endif
56 #if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
57 # ifdef __linux__
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
62 # endif
63 #endif
65 #if FFI_CLOSURES
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 */
73 #define USE_LOCKS 1
74 #define USE_DL_PREFIX 1
75 #ifdef __GNUC__
76 #ifndef USE_BUILTIN_FFS
77 #define USE_BUILTIN_FFS 1
78 #endif
79 #endif
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. */
85 #define HAVE_MREMAP 0
87 /* We have no use for this, so save some code and data. */
88 #define NO_MALLINFO 1
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)
97 #if FFI_CLOSURE_TEST
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)
103 #endif
105 #include <sys/types.h>
106 #include <sys/stat.h>
107 #include <fcntl.h>
108 #include <errno.h>
109 #ifndef _MSC_VER
110 #include <unistd.h>
111 #endif
112 #include <string.h>
113 #include <stdio.h>
114 #if !defined(X86_WIN32) && !defined(X86_WIN64)
115 #ifdef HAVE_MNTENT
116 #include <mntent.h>
117 #endif /* HAVE_MNTENT */
118 #include <sys/param.h>
119 #include <pthread.h>
121 /* We don't want sys/mman.h to be included after we redefine mmap and
122 dlmunmap. */
123 #include <sys/mman.h>
124 #define LACKS_SYS_MMAN_H 1
126 #if FFI_MMAP_EXEC_SELINUX
127 #include <sys/statfs.h>
128 #include <stdlib.h>
130 static int selinux_enabled = -1;
132 static int
133 selinux_enabled_check (void)
135 struct statfs sfs;
136 FILE *f;
137 char *buf = NULL;
138 size_t len = 0;
140 if (statfs ("/selinux", &sfs) >= 0
141 && (unsigned int) sfs.f_type == 0xf97cff8cU)
142 return 1;
143 f = fopen ("/proc/mounts", "r");
144 if (f == NULL)
145 return 0;
146 while (getline (&buf, &len, f) >= 0)
148 char *p = strchr (buf, ' ');
149 if (p == NULL)
150 break;
151 p = strchr (p + 1, ' ');
152 if (p == NULL)
153 break;
154 if (strncmp (p + 1, "selinuxfs ", 10) == 0)
156 free (buf);
157 fclose (f);
158 return 1;
161 free (buf);
162 fclose (f);
163 return 0;
166 #define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
167 : (selinux_enabled = selinux_enabled_check ()))
169 #else
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
177 #include <stdlib.h>
179 static int emutramp_enabled = -1;
181 static int
182 emutramp_enabled_check (void)
184 if (getenv ("FFI_DISABLE_EMUTRAMP") == NULL)
185 return 1;
186 else
187 return 0;
190 #define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
191 : (emutramp_enabled = emutramp_enabled_check ()))
192 #else
193 #define is_emutramp_enabled() 0
194 #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
196 #elif defined (__CYGWIN__) || defined(__INTERIX)
198 #include <sys/mman.h>
200 /* Cygwin is Linux-like, but not quite that Linux-like. */
201 #define is_selinux_enabled() 0
203 #endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
205 /* Declare all functions defined in dlmalloc.c as static. */
206 static void *dlmalloc(size_t);
207 static void dlfree(void*);
208 static void *dlcalloc(size_t, size_t) MAYBE_UNUSED;
209 static void *dlrealloc(void *, size_t) MAYBE_UNUSED;
210 static void *dlmemalign(size_t, size_t) MAYBE_UNUSED;
211 static void *dlvalloc(size_t) MAYBE_UNUSED;
212 static int dlmallopt(int, int) MAYBE_UNUSED;
213 static size_t dlmalloc_footprint(void) MAYBE_UNUSED;
214 static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED;
215 static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED;
216 static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED;
217 static void *dlpvalloc(size_t) MAYBE_UNUSED;
218 static int dlmalloc_trim(size_t) MAYBE_UNUSED;
219 static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
220 static void dlmalloc_stats(void) MAYBE_UNUSED;
222 #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
223 /* Use these for mmap and munmap within dlmalloc.c. */
224 static void *dlmmap(void *, size_t, int, int, int, off_t);
225 static int dlmunmap(void *, size_t);
226 #endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
228 #define mmap dlmmap
229 #define munmap dlmunmap
231 #include "dlmalloc.c"
233 #undef mmap
234 #undef munmap
236 #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
238 /* A mutex used to synchronize access to *exec* variables in this file. */
239 static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
241 /* A file descriptor of a temporary file from which we'll map
242 executable pages. */
243 static int execfd = -1;
245 /* The amount of space already allocated from the temporary file. */
246 static size_t execsize = 0;
248 /* Open a temporary file name, and immediately unlink it. */
249 static int
250 open_temp_exec_file_name (char *name)
252 int fd = mkstemp (name);
254 if (fd != -1)
255 unlink (name);
257 return fd;
260 /* Open a temporary file in the named directory. */
261 static int
262 open_temp_exec_file_dir (const char *dir)
264 static const char suffix[] = "/ffiXXXXXX";
265 int lendir = strlen (dir);
266 char *tempname = __builtin_alloca (lendir + sizeof (suffix));
268 if (!tempname)
269 return -1;
271 memcpy (tempname, dir, lendir);
272 memcpy (tempname + lendir, suffix, sizeof (suffix));
274 return open_temp_exec_file_name (tempname);
277 /* Open a temporary file in the directory in the named environment
278 variable. */
279 static int
280 open_temp_exec_file_env (const char *envvar)
282 const char *value = getenv (envvar);
284 if (!value)
285 return -1;
287 return open_temp_exec_file_dir (value);
290 #ifdef HAVE_MNTENT
291 /* Open a temporary file in an executable and writable mount point
292 listed in the mounts file. Subsequent calls with the same mounts
293 keep searching for mount points in the same file. Providing NULL
294 as the mounts file closes the file. */
295 static int
296 open_temp_exec_file_mnt (const char *mounts)
298 static const char *last_mounts;
299 static FILE *last_mntent;
301 if (mounts != last_mounts)
303 if (last_mntent)
304 endmntent (last_mntent);
306 last_mounts = mounts;
308 if (mounts)
309 last_mntent = setmntent (mounts, "r");
310 else
311 last_mntent = NULL;
314 if (!last_mntent)
315 return -1;
317 for (;;)
319 int fd;
320 struct mntent mnt;
321 char buf[MAXPATHLEN * 3];
323 if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)) == NULL)
324 return -1;
326 if (hasmntopt (&mnt, "ro")
327 || hasmntopt (&mnt, "noexec")
328 || access (mnt.mnt_dir, W_OK))
329 continue;
331 fd = open_temp_exec_file_dir (mnt.mnt_dir);
333 if (fd != -1)
334 return fd;
337 #endif /* HAVE_MNTENT */
339 /* Instructions to look for a location to hold a temporary file that
340 can be mapped in for execution. */
341 static struct
343 int (*func)(const char *);
344 const char *arg;
345 int repeat;
346 } open_temp_exec_file_opts[] = {
347 { open_temp_exec_file_env, "TMPDIR", 0 },
348 { open_temp_exec_file_dir, "/tmp", 0 },
349 { open_temp_exec_file_dir, "/var/tmp", 0 },
350 { open_temp_exec_file_dir, "/dev/shm", 0 },
351 { open_temp_exec_file_env, "HOME", 0 },
352 #ifdef HAVE_MNTENT
353 { open_temp_exec_file_mnt, "/etc/mtab", 1 },
354 { open_temp_exec_file_mnt, "/proc/mounts", 1 },
355 #endif /* HAVE_MNTENT */
358 /* Current index into open_temp_exec_file_opts. */
359 static int open_temp_exec_file_opts_idx = 0;
361 /* Reset a current multi-call func, then advances to the next entry.
362 If we're at the last, go back to the first and return nonzero,
363 otherwise return zero. */
364 static int
365 open_temp_exec_file_opts_next (void)
367 if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
368 open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
370 open_temp_exec_file_opts_idx++;
371 if (open_temp_exec_file_opts_idx
372 == (sizeof (open_temp_exec_file_opts)
373 / sizeof (*open_temp_exec_file_opts)))
375 open_temp_exec_file_opts_idx = 0;
376 return 1;
379 return 0;
382 /* Return a file descriptor of a temporary zero-sized file in a
383 writable and exexutable filesystem. */
384 static int
385 open_temp_exec_file (void)
387 int fd;
391 fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
392 (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
394 if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
395 || fd == -1)
397 if (open_temp_exec_file_opts_next ())
398 break;
401 while (fd == -1);
403 return fd;
406 /* Map in a chunk of memory from the temporary exec file into separate
407 locations in the virtual memory address space, one writable and one
408 executable. Returns the address of the writable portion, after
409 storing an offset to the corresponding executable portion at the
410 last word of the requested chunk. */
411 static void *
412 dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
414 void *ptr;
416 if (execfd == -1)
418 open_temp_exec_file_opts_idx = 0;
419 retry_open:
420 execfd = open_temp_exec_file ();
421 if (execfd == -1)
422 return MFAIL;
425 offset = execsize;
427 if (ftruncate (execfd, offset + length))
428 return MFAIL;
430 flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
431 flags |= MAP_SHARED;
433 ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
434 flags, execfd, offset);
435 if (ptr == MFAIL)
437 if (!offset)
439 close (execfd);
440 goto retry_open;
442 ftruncate (execfd, offset);
443 return MFAIL;
445 else if (!offset
446 && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
447 open_temp_exec_file_opts_next ();
449 start = mmap (start, length, prot, flags, execfd, offset);
451 if (start == MFAIL)
453 munmap (ptr, length);
454 ftruncate (execfd, offset);
455 return start;
458 mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
460 execsize += length;
462 return start;
465 /* Map in a writable and executable chunk of memory if possible.
466 Failing that, fall back to dlmmap_locked. */
467 static void *
468 dlmmap (void *start, size_t length, int prot,
469 int flags, int fd, off_t offset)
471 void *ptr;
473 assert (start == NULL && length % malloc_getpagesize == 0
474 && prot == (PROT_READ | PROT_WRITE)
475 && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
476 && fd == -1 && offset == 0);
478 #if FFI_CLOSURE_TEST
479 printf ("mapping in %zi\n", length);
480 #endif
482 if (execfd == -1 && is_emutramp_enabled ())
484 ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
485 return ptr;
488 if (execfd == -1 && !is_selinux_enabled ())
490 ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
492 if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
493 /* Cool, no need to mess with separate segments. */
494 return ptr;
496 /* If MREMAP_DUP is ever introduced and implemented, try mmap
497 with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
498 MREMAP_DUP and prot at this point. */
501 if (execsize == 0 || execfd == -1)
503 pthread_mutex_lock (&open_temp_exec_file_mutex);
504 ptr = dlmmap_locked (start, length, prot, flags, offset);
505 pthread_mutex_unlock (&open_temp_exec_file_mutex);
507 return ptr;
510 return dlmmap_locked (start, length, prot, flags, offset);
513 /* Release memory at the given address, as well as the corresponding
514 executable page if it's separate. */
515 static int
516 dlmunmap (void *start, size_t length)
518 /* We don't bother decreasing execsize or truncating the file, since
519 we can't quite tell whether we're unmapping the end of the file.
520 We don't expect frequent deallocation anyway. If we did, we
521 could locate pages in the file by writing to the pages being
522 deallocated and checking that the file contents change.
523 Yuck. */
524 msegmentptr seg = segment_holding (gm, start);
525 void *code;
527 #if FFI_CLOSURE_TEST
528 printf ("unmapping %zi\n", length);
529 #endif
531 if (seg && (code = add_segment_exec_offset (start, seg)) != start)
533 int ret = munmap (code, length);
534 if (ret)
535 return ret;
538 return munmap (start, length);
541 #if FFI_CLOSURE_FREE_CODE
542 /* Return segment holding given code address. */
543 static msegmentptr
544 segment_holding_code (mstate m, char* addr)
546 msegmentptr sp = &m->seg;
547 for (;;) {
548 if (addr >= add_segment_exec_offset (sp->base, sp)
549 && addr < add_segment_exec_offset (sp->base, sp) + sp->size)
550 return sp;
551 if ((sp = sp->next) == 0)
552 return 0;
555 #endif
557 #endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
559 /* Allocate a chunk of memory with the given size. Returns a pointer
560 to the writable address, and sets *CODE to the executable
561 corresponding virtual address. */
562 void *
563 ffi_closure_alloc (size_t size, void **code)
565 void *ptr;
567 if (!code)
568 return NULL;
570 ptr = dlmalloc (size);
572 if (ptr)
574 msegmentptr seg = segment_holding (gm, ptr);
576 *code = add_segment_exec_offset (ptr, seg);
579 return ptr;
582 /* Release a chunk of memory allocated with ffi_closure_alloc. If
583 FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
584 writable or the executable address given. Otherwise, only the
585 writable address can be provided here. */
586 void
587 ffi_closure_free (void *ptr)
589 #if FFI_CLOSURE_FREE_CODE
590 msegmentptr seg = segment_holding_code (gm, ptr);
592 if (seg)
593 ptr = sub_segment_exec_offset (ptr, seg);
594 #endif
596 dlfree (ptr);
600 #if FFI_CLOSURE_TEST
601 /* Do some internal sanity testing to make sure allocation and
602 deallocation of pages are working as intended. */
603 int main ()
605 void *p[3];
606 #define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
607 #define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
608 GET (0, malloc_getpagesize / 2);
609 GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
610 PUT (1);
611 GET (1, 2 * malloc_getpagesize);
612 GET (2, malloc_getpagesize / 2);
613 PUT (1);
614 PUT (0);
615 PUT (2);
616 return 0;
618 #endif /* FFI_CLOSURE_TEST */
619 # else /* ! FFI_MMAP_EXEC_WRIT */
621 /* On many systems, memory returned by malloc is writable and
622 executable, so just use it. */
624 #include <stdlib.h>
626 void *
627 ffi_closure_alloc (size_t size, void **code)
629 if (!code)
630 return NULL;
632 return *code = malloc (size);
635 void
636 ffi_closure_free (void *ptr)
638 free (ptr);
641 # endif /* ! FFI_MMAP_EXEC_WRIT */
642 #endif /* FFI_CLOSURES */