OSDN Git Service

Improve libffi comments
[pf3gnuchains/gcc-fork.git] / libffi / src / closures.c
1 /* -----------------------------------------------------------------------
2    closures.c - Copyright (c) 2007  Red Hat, Inc.
3    Copyright (C) 2007, 2009 Free Software Foundation, Inc
4
5    Code to allocate and deallocate memory for closures.
6
7    Permission is hereby granted, free of charge, to any person obtaining
8    a copy of this software and associated documentation files (the
9    ``Software''), to deal in the Software without restriction, including
10    without limitation the rights to use, copy, modify, merge, publish,
11    distribute, sublicense, and/or sell copies of the Software, and to
12    permit persons to whom the Software is furnished to do so, subject to
13    the following conditions:
14
15    The above copyright notice and this permission notice shall be included
16    in all copies or substantial portions of the Software.
17
18    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25    DEALINGS IN THE SOFTWARE.
26    ----------------------------------------------------------------------- */
27
28 #if defined __linux__ && !defined _GNU_SOURCE
29 #define _GNU_SOURCE 1
30 #endif
31
32 #include <ffi.h>
33 #include <ffi_common.h>
34
35 #ifndef FFI_MMAP_EXEC_WRIT
36 # if __gnu_linux__
37 /* This macro indicates it may be forbidden to map anonymous memory
38    with both write and execute permission.  Code compiled when this
39    option is defined will attempt to map such pages once, but if it
40    fails, it falls back to creating a temporary file in a writable and
41    executable filesystem and mapping pages from it into separate
42    locations in the virtual memory space, one location writable and
43    another executable.  */
44 #  define FFI_MMAP_EXEC_WRIT 1
45 #  define HAVE_MNTENT 1
46 # endif
47 # if defined(X86_WIN32) || defined(X86_WIN64)
48 /* Windows systems may have Data Execution Protection (DEP) enabled, 
49    which requires the use of VirtualMalloc/VirtualFree to alloc/free
50    executable memory. */
51 #  define FFI_MMAP_EXEC_WRIT 1
52 # endif
53 #endif
54
55 #if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
56 # ifdef __linux__
57 /* When defined to 1 check for SELinux and if SELinux is active,
58    don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
59    might cause audit messages.  */
60 #  define FFI_MMAP_EXEC_SELINUX 1
61 # endif
62 #endif
63
64 #if FFI_CLOSURES
65
66 # if FFI_MMAP_EXEC_WRIT
67
68 #define USE_LOCKS 1
69 #define USE_DL_PREFIX 1
70 #ifdef __GNUC__
71 #ifndef USE_BUILTIN_FFS
72 #define USE_BUILTIN_FFS 1
73 #endif
74 #endif
75
76 /* We need to use mmap, not sbrk.  */
77 #define HAVE_MORECORE 0
78
79 /* We could, in theory, support mremap, but it wouldn't buy us anything.  */
80 #define HAVE_MREMAP 0
81
82 /* We have no use for this, so save some code and data.  */
83 #define NO_MALLINFO 1
84
85 /* We need all allocations to be in regular segments, otherwise we
86    lose track of the corresponding code address.  */
87 #define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
88
89 /* Don't allocate more than a page unless needed.  */
90 #define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
91
92 #if FFI_CLOSURE_TEST
93 /* Don't release single pages, to avoid a worst-case scenario of
94    continuously allocating and releasing single pages, but release
95    pairs of pages, which should do just as well given that allocations
96    are likely to be small.  */
97 #define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
98 #endif
99
100 #include <sys/types.h>
101 #include <sys/stat.h>
102 #include <fcntl.h>
103 #include <errno.h>
104 #ifndef _MSC_VER
105 #include <unistd.h>
106 #endif
107 #include <string.h>
108 #include <stdio.h>
109 #if !defined(X86_WIN32) && !defined(X86_WIN64)
110 #ifdef HAVE_MNTENT
111 #include <mntent.h>
112 #endif /* HAVE_MNTENT */
113 #include <sys/param.h>
114 #include <pthread.h>
115
116 /* We don't want sys/mman.h to be included after we redefine mmap and
117    dlmunmap.  */
118 #include <sys/mman.h>
119 #define LACKS_SYS_MMAN_H 1
120
121 #if FFI_MMAP_EXEC_SELINUX
122 #include <sys/statfs.h>
123 #include <stdlib.h>
124
125 static int selinux_enabled = -1;
126
127 static int
128 selinux_enabled_check (void)
129 {
130   struct statfs sfs;
131   FILE *f;
132   char *buf = NULL;
133   size_t len = 0;
134
135   if (statfs ("/selinux", &sfs) >= 0
136       && (unsigned int) sfs.f_type == 0xf97cff8cU)
137     return 1;
138   f = fopen ("/proc/mounts", "r");
139   if (f == NULL)
140     return 0;
141   while (getline (&buf, &len, f) >= 0)
142     {
143       char *p = strchr (buf, ' ');
144       if (p == NULL)
145         break;
146       p = strchr (p + 1, ' ');
147       if (p == NULL)
148         break;
149       if (strncmp (p + 1, "selinuxfs ", 10) != 0)
150         {
151           free (buf);
152           fclose (f);
153           return 1;
154         }
155     }
156   free (buf);
157   fclose (f);
158   return 0;
159 }
160
161 #define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
162                               : (selinux_enabled = selinux_enabled_check ()))
163
164 #else
165
166 #define is_selinux_enabled() 0
167
168 #endif /* !FFI_MMAP_EXEC_SELINUX */
169
170 #elif defined (__CYGWIN__)
171
172 #include <sys/mman.h>
173
174 /* Cygwin is Linux-like, but not quite that Linux-like.  */
175 #define is_selinux_enabled() 0
176
177 #endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
178
179 /* Declare all functions defined in dlmalloc.c as static.  */
180 static void *dlmalloc(size_t);
181 static void dlfree(void*);
182 static void *dlcalloc(size_t, size_t) MAYBE_UNUSED;
183 static void *dlrealloc(void *, size_t) MAYBE_UNUSED;
184 static void *dlmemalign(size_t, size_t) MAYBE_UNUSED;
185 static void *dlvalloc(size_t) MAYBE_UNUSED;
186 static int dlmallopt(int, int) MAYBE_UNUSED;
187 static size_t dlmalloc_footprint(void) MAYBE_UNUSED;
188 static size_t dlmalloc_max_footprint(void) MAYBE_UNUSED;
189 static void** dlindependent_calloc(size_t, size_t, void**) MAYBE_UNUSED;
190 static void** dlindependent_comalloc(size_t, size_t*, void**) MAYBE_UNUSED;
191 static void *dlpvalloc(size_t) MAYBE_UNUSED;
192 static int dlmalloc_trim(size_t) MAYBE_UNUSED;
193 static size_t dlmalloc_usable_size(void*) MAYBE_UNUSED;
194 static void dlmalloc_stats(void) MAYBE_UNUSED;
195
196 #if !(defined(X86_WIN32) || defined(X86_WIN64)) || defined (__CYGWIN__)
197 /* Use these for mmap and munmap within dlmalloc.c.  */
198 static void *dlmmap(void *, size_t, int, int, int, off_t);
199 static int dlmunmap(void *, size_t);
200 #endif /* !(defined(X86_WIN32) || defined(X86_WIN64)) || defined (__CYGWIN__) */
201
202 #define mmap dlmmap
203 #define munmap dlmunmap
204
205 #include "dlmalloc.c"
206
207 #undef mmap
208 #undef munmap
209
210 #if !(defined(X86_WIN32) || defined(X86_WIN64)) || defined (__CYGWIN__)
211
212 /* A mutex used to synchronize access to *exec* variables in this file.  */
213 static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
214
215 /* A file descriptor of a temporary file from which we'll map
216    executable pages.  */
217 static int execfd = -1;
218
219 /* The amount of space already allocated from the temporary file.  */
220 static size_t execsize = 0;
221
222 /* Open a temporary file name, and immediately unlink it.  */
223 static int
224 open_temp_exec_file_name (char *name)
225 {
226   int fd = mkstemp (name);
227
228   if (fd != -1)
229     unlink (name);
230
231   return fd;
232 }
233
234 /* Open a temporary file in the named directory.  */
235 static int
236 open_temp_exec_file_dir (const char *dir)
237 {
238   static const char suffix[] = "/ffiXXXXXX";
239   int lendir = strlen (dir);
240   char *tempname = __builtin_alloca (lendir + sizeof (suffix));
241
242   if (!tempname)
243     return -1;
244
245   memcpy (tempname, dir, lendir);
246   memcpy (tempname + lendir, suffix, sizeof (suffix));
247
248   return open_temp_exec_file_name (tempname);
249 }
250
251 /* Open a temporary file in the directory in the named environment
252    variable.  */
253 static int
254 open_temp_exec_file_env (const char *envvar)
255 {
256   const char *value = getenv (envvar);
257
258   if (!value)
259     return -1;
260
261   return open_temp_exec_file_dir (value);
262 }
263
264 #ifdef HAVE_MNTENT
265 /* Open a temporary file in an executable and writable mount point
266    listed in the mounts file.  Subsequent calls with the same mounts
267    keep searching for mount points in the same file.  Providing NULL
268    as the mounts file closes the file.  */
269 static int
270 open_temp_exec_file_mnt (const char *mounts)
271 {
272   static const char *last_mounts;
273   static FILE *last_mntent;
274
275   if (mounts != last_mounts)
276     {
277       if (last_mntent)
278         endmntent (last_mntent);
279
280       last_mounts = mounts;
281
282       if (mounts)
283         last_mntent = setmntent (mounts, "r");
284       else
285         last_mntent = NULL;
286     }
287
288   if (!last_mntent)
289     return -1;
290
291   for (;;)
292     {
293       int fd;
294       struct mntent mnt;
295       char buf[MAXPATHLEN * 3];
296
297       if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)))
298         return -1;
299
300       if (hasmntopt (&mnt, "ro")
301           || hasmntopt (&mnt, "noexec")
302           || access (mnt.mnt_dir, W_OK))
303         continue;
304
305       fd = open_temp_exec_file_dir (mnt.mnt_dir);
306
307       if (fd != -1)
308         return fd;
309     }
310 }
311 #endif /* HAVE_MNTENT */
312
313 /* Instructions to look for a location to hold a temporary file that
314    can be mapped in for execution.  */
315 static struct
316 {
317   int (*func)(const char *);
318   const char *arg;
319   int repeat;
320 } open_temp_exec_file_opts[] = {
321   { open_temp_exec_file_env, "TMPDIR", 0 },
322   { open_temp_exec_file_dir, "/tmp", 0 },
323   { open_temp_exec_file_dir, "/var/tmp", 0 },
324   { open_temp_exec_file_dir, "/dev/shm", 0 },
325   { open_temp_exec_file_env, "HOME", 0 },
326 #ifdef HAVE_MNTENT
327   { open_temp_exec_file_mnt, "/etc/mtab", 1 },
328   { open_temp_exec_file_mnt, "/proc/mounts", 1 },
329 #endif /* HAVE_MNTENT */
330 };
331
332 /* Current index into open_temp_exec_file_opts.  */
333 static int open_temp_exec_file_opts_idx = 0;
334
335 /* Reset a current multi-call func, then advances to the next entry.
336    If we're at the last, go back to the first and return nonzero,
337    otherwise return zero.  */
338 static int
339 open_temp_exec_file_opts_next (void)
340 {
341   if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
342     open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
343
344   open_temp_exec_file_opts_idx++;
345   if (open_temp_exec_file_opts_idx
346       == (sizeof (open_temp_exec_file_opts)
347           / sizeof (*open_temp_exec_file_opts)))
348     {
349       open_temp_exec_file_opts_idx = 0;
350       return 1;
351     }
352
353   return 0;
354 }
355
356 /* Return a file descriptor of a temporary zero-sized file in a
357    writable and exexutable filesystem.  */
358 static int
359 open_temp_exec_file (void)
360 {
361   int fd;
362
363   do
364     {
365       fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
366         (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
367
368       if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
369           || fd == -1)
370         {
371           if (open_temp_exec_file_opts_next ())
372             break;
373         }
374     }
375   while (fd == -1);
376
377   return fd;
378 }
379
380 /* Map in a chunk of memory from the temporary exec file into separate
381    locations in the virtual memory address space, one writable and one
382    executable.  Returns the address of the writable portion, after
383    storing an offset to the corresponding executable portion at the
384    last word of the requested chunk.  */
385 static void *
386 dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
387 {
388   void *ptr;
389
390   if (execfd == -1)
391     {
392       open_temp_exec_file_opts_idx = 0;
393     retry_open:
394       execfd = open_temp_exec_file ();
395       if (execfd == -1)
396         return MFAIL;
397     }
398
399   offset = execsize;
400
401   if (ftruncate (execfd, offset + length))
402     return MFAIL;
403
404   flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
405   flags |= MAP_SHARED;
406
407   ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
408               flags, execfd, offset);
409   if (ptr == MFAIL)
410     {
411       if (!offset)
412         {
413           close (execfd);
414           goto retry_open;
415         }
416       ftruncate (execfd, offset);
417       return MFAIL;
418     }
419   else if (!offset
420            && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
421     open_temp_exec_file_opts_next ();
422
423   start = mmap (start, length, prot, flags, execfd, offset);
424
425   if (start == MFAIL)
426     {
427       munmap (ptr, length);
428       ftruncate (execfd, offset);
429       return start;
430     }
431
432   mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
433
434   execsize += length;
435
436   return start;
437 }
438
439 /* Map in a writable and executable chunk of memory if possible.
440    Failing that, fall back to dlmmap_locked.  */
441 static void *
442 dlmmap (void *start, size_t length, int prot,
443         int flags, int fd, off_t offset)
444 {
445   void *ptr;
446
447   assert (start == NULL && length % malloc_getpagesize == 0
448           && prot == (PROT_READ | PROT_WRITE)
449           && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
450           && fd == -1 && offset == 0);
451
452 #if FFI_CLOSURE_TEST
453   printf ("mapping in %zi\n", length);
454 #endif
455
456   if (execfd == -1 && !is_selinux_enabled ())
457     {
458       ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
459
460       if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
461         /* Cool, no need to mess with separate segments.  */
462         return ptr;
463
464       /* If MREMAP_DUP is ever introduced and implemented, try mmap
465          with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
466          MREMAP_DUP and prot at this point.  */
467     }
468
469   if (execsize == 0 || execfd == -1)
470     {
471       pthread_mutex_lock (&open_temp_exec_file_mutex);
472       ptr = dlmmap_locked (start, length, prot, flags, offset);
473       pthread_mutex_unlock (&open_temp_exec_file_mutex);
474
475       return ptr;
476     }
477
478   return dlmmap_locked (start, length, prot, flags, offset);
479 }
480
481 /* Release memory at the given address, as well as the corresponding
482    executable page if it's separate.  */
483 static int
484 dlmunmap (void *start, size_t length)
485 {
486   /* We don't bother decreasing execsize or truncating the file, since
487      we can't quite tell whether we're unmapping the end of the file.
488      We don't expect frequent deallocation anyway.  If we did, we
489      could locate pages in the file by writing to the pages being
490      deallocated and checking that the file contents change.
491      Yuck.  */
492   msegmentptr seg = segment_holding (gm, start);
493   void *code;
494
495 #if FFI_CLOSURE_TEST
496   printf ("unmapping %zi\n", length);
497 #endif
498
499   if (seg && (code = add_segment_exec_offset (start, seg)) != start)
500     {
501       int ret = munmap (code, length);
502       if (ret)
503         return ret;
504     }
505
506   return munmap (start, length);
507 }
508
509 #if FFI_CLOSURE_FREE_CODE
510 /* Return segment holding given code address.  */
511 static msegmentptr
512 segment_holding_code (mstate m, char* addr)
513 {
514   msegmentptr sp = &m->seg;
515   for (;;) {
516     if (addr >= add_segment_exec_offset (sp->base, sp)
517         && addr < add_segment_exec_offset (sp->base, sp) + sp->size)
518       return sp;
519     if ((sp = sp->next) == 0)
520       return 0;
521   }
522 }
523 #endif
524
525 #endif /* !(defined(X86_WIN32) || defined(X86_WIN64)) || defined (__CYGWIN__) */
526
527 /* Allocate a chunk of memory with the given size.  Returns a pointer
528    to the writable address, and sets *CODE to the executable
529    corresponding virtual address.  */
530 void *
531 ffi_closure_alloc (size_t size, void **code)
532 {
533   void *ptr;
534
535   if (!code)
536     return NULL;
537
538   ptr = dlmalloc (size);
539
540   if (ptr)
541     {
542       msegmentptr seg = segment_holding (gm, ptr);
543
544       *code = add_segment_exec_offset (ptr, seg);
545     }
546
547   return ptr;
548 }
549
550 /* Release a chunk of memory allocated with ffi_closure_alloc.  If
551    FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
552    writable or the executable address given.  Otherwise, only the
553    writable address can be provided here.  */
554 void
555 ffi_closure_free (void *ptr)
556 {
557 #if FFI_CLOSURE_FREE_CODE
558   msegmentptr seg = segment_holding_code (gm, ptr);
559
560   if (seg)
561     ptr = sub_segment_exec_offset (ptr, seg);
562 #endif
563
564   dlfree (ptr);
565 }
566
567
568 #if FFI_CLOSURE_TEST
569 /* Do some internal sanity testing to make sure allocation and
570    deallocation of pages are working as intended.  */
571 int main ()
572 {
573   void *p[3];
574 #define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
575 #define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
576   GET (0, malloc_getpagesize / 2);
577   GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
578   PUT (1);
579   GET (1, 2 * malloc_getpagesize);
580   GET (2, malloc_getpagesize / 2);
581   PUT (1);
582   PUT (0);
583   PUT (2);
584   return 0;
585 }
586 #endif /* FFI_CLOSURE_TEST */
587 # else /* ! FFI_MMAP_EXEC_WRIT */
588
589 /* On many systems, memory returned by malloc is writable and
590    executable, so just use it.  */
591
592 #include <stdlib.h>
593
594 void *
595 ffi_closure_alloc (size_t size, void **code)
596 {
597   if (!code)
598     return NULL;
599
600   return *code = malloc (size);
601 }
602
603 void
604 ffi_closure_free (void *ptr)
605 {
606   free (ptr);
607 }
608
609 # endif /* ! FFI_MMAP_EXEC_WRIT */
610 #endif /* FFI_CLOSURES */