LCOV - code coverage report
Current view: top level - js/src/ctypes/libffi/src - closures.c (source / functions) Hit Total Coverage
Test: output.info Lines: 0 137 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       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.
       5             : 
       6             :    Code to allocate and deallocate memory for closures.
       7             : 
       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:
      15             : 
      16             :    The above copyright notice and this permission notice shall be included
      17             :    in all copies or substantial portions of the Software.
      18             : 
      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             :    ----------------------------------------------------------------------- */
      28             : 
      29             : #if defined __linux__ && !defined _GNU_SOURCE
      30             : #define _GNU_SOURCE 1
      31             : #endif
      32             : 
      33             : #include <ffi.h>
      34             : #include <ffi_common.h>
      35             : 
      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
      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
      55             : 
      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
      64             : 
      65             : #if FFI_CLOSURES
      66             : 
      67             : # if FFI_EXEC_TRAMPOLINE_TABLE
      68             : 
      69             : // Per-target implementation; It's unclear what can reasonable be shared between two OS/architecture implementations.
      70             : 
      71             : # elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
      72             : 
      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
      80             : 
      81             : /* We need to use mmap, not sbrk.  */
      82             : #define HAVE_MORECORE 0
      83             : 
      84             : /* We could, in theory, support mremap, but it wouldn't buy us anything.  */
      85             : #define HAVE_MREMAP 0
      86             : 
      87             : /* We have no use for this, so save some code and data.  */
      88             : #define NO_MALLINFO 1
      89             : 
      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
      93             : 
      94             : /* Don't allocate more than a page unless needed.  */
      95             : #define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
      96             : 
      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
     104             : 
     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>
     120             : 
     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
     125             : 
     126             : #if FFI_MMAP_EXEC_SELINUX
     127             : #include <sys/statfs.h>
     128             : #include <stdlib.h>
     129             : 
     130             : static int selinux_enabled = -1;
     131             : 
     132             : static int
     133           0 : selinux_enabled_check (void)
     134             : {
     135             :   struct statfs sfs;
     136             :   FILE *f;
     137           0 :   char *buf = NULL;
     138           0 :   size_t len = 0;
     139             : 
     140           0 :   if (statfs ("/selinux", &sfs) >= 0
     141           0 :       && (unsigned int) sfs.f_type == 0xf97cff8cU)
     142           0 :     return 1;
     143           0 :   f = fopen ("/proc/mounts", "r");
     144           0 :   if (f == NULL)
     145           0 :     return 0;
     146           0 :   while (getline (&buf, &len, f) >= 0)
     147             :     {
     148           0 :       char *p = strchr (buf, ' ');
     149           0 :       if (p == NULL)
     150           0 :         break;
     151           0 :       p = strchr (p + 1, ' ');
     152           0 :       if (p == NULL)
     153           0 :         break;
     154           0 :       if (strncmp (p + 1, "selinuxfs ", 10) == 0)
     155             :         {
     156           0 :           free (buf);
     157           0 :           fclose (f);
     158           0 :           return 1;
     159             :         }
     160             :     }
     161           0 :   free (buf);
     162           0 :   fclose (f);
     163           0 :   return 0;
     164             : }
     165             : 
     166             : #define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
     167             :                               : (selinux_enabled = selinux_enabled_check ()))
     168             : 
     169             : #else
     170             : 
     171             : #define is_selinux_enabled() 0
     172             : 
     173             : #endif /* !FFI_MMAP_EXEC_SELINUX */
     174             : 
     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>
     178             : 
     179             : static int emutramp_enabled = -1;
     180             : 
     181             : static int
     182             : emutramp_enabled_check (void)
     183             : {
     184             :   char *buf = NULL;
     185             :   size_t len = 0;
     186             :   FILE *f;
     187             :   int ret;
     188             :   f = fopen ("/proc/self/status", "r");
     189             :   if (f == NULL)
     190             :     return 0;
     191             :   ret = 0;
     192             : 
     193             :   while (getline (&buf, &len, f) != -1)
     194             :     if (!strncmp (buf, "PaX:", 4))
     195             :       {
     196             :         char emutramp;
     197             :         if (sscanf (buf, "%*s %*c%c", &emutramp) == 1)
     198             :           ret = (emutramp == 'E');
     199             :         break;
     200             :       }
     201             :   free (buf);
     202             :   fclose (f);
     203             :   return ret;
     204             : }
     205             : 
     206             : #define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
     207             :                                : (emutramp_enabled = emutramp_enabled_check ()))
     208             : #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
     209             : 
     210             : #elif defined (__CYGWIN__) || defined(__INTERIX)
     211             : 
     212             : #include <sys/mman.h>
     213             : 
     214             : /* Cygwin is Linux-like, but not quite that Linux-like.  */
     215             : #define is_selinux_enabled() 0
     216             : 
     217             : #endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
     218             : 
     219             : #ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
     220             : #define is_emutramp_enabled() 0
     221             : #endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
     222             : 
     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;
     239             : 
     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) */
     245             : 
     246             : #define mmap dlmmap
     247             : #define munmap dlmunmap
     248             : 
     249             : #include "dlmalloc.c"
     250             : 
     251             : #undef mmap
     252             : #undef munmap
     253             : 
     254             : #if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
     255             : 
     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;
     258             : 
     259             : /* A file descriptor of a temporary file from which we'll map
     260             :    executable pages.  */
     261             : static int execfd = -1;
     262             : 
     263             : /* The amount of space already allocated from the temporary file.  */
     264             : static size_t execsize = 0;
     265             : 
     266             : /* Open a temporary file name, and immediately unlink it.  */
     267             : static int
     268           0 : open_temp_exec_file_name (char *name)
     269             : {
     270           0 :   int fd = mkstemp (name);
     271             : 
     272           0 :   if (fd != -1)
     273           0 :     unlink (name);
     274             : 
     275           0 :   return fd;
     276             : }
     277             : 
     278             : /* Open a temporary file in the named directory.  */
     279             : static int
     280           0 : open_temp_exec_file_dir (const char *dir)
     281             : {
     282             :   static const char suffix[] = "/ffiXXXXXX";
     283           0 :   size_t lendir = strlen (dir);
     284           0 :   char *tempname = __builtin_alloca (lendir + sizeof (suffix));
     285             : 
     286           0 :   if (!tempname)
     287           0 :     return -1;
     288             : 
     289           0 :   memcpy (tempname, dir, lendir);
     290           0 :   memcpy (tempname + lendir, suffix, sizeof (suffix));
     291             : 
     292           0 :   return open_temp_exec_file_name (tempname);
     293             : }
     294             : 
     295             : /* Open a temporary file in the directory in the named environment
     296             :    variable.  */
     297             : static int
     298           0 : open_temp_exec_file_env (const char *envvar)
     299             : {
     300           0 :   const char *value = getenv (envvar);
     301             : 
     302           0 :   if (!value)
     303           0 :     return -1;
     304             : 
     305           0 :   return open_temp_exec_file_dir (value);
     306             : }
     307             : 
     308             : #ifdef HAVE_MNTENT
     309             : /* Open a temporary file in an executable and writable mount point
     310             :    listed in the mounts file.  Subsequent calls with the same mounts
     311             :    keep searching for mount points in the same file.  Providing NULL
     312             :    as the mounts file closes the file.  */
     313             : static int
     314           0 : open_temp_exec_file_mnt (const char *mounts)
     315             : {
     316             :   static const char *last_mounts;
     317             :   static FILE *last_mntent;
     318             : 
     319           0 :   if (mounts != last_mounts)
     320             :     {
     321           0 :       if (last_mntent)
     322           0 :         endmntent (last_mntent);
     323             : 
     324           0 :       last_mounts = mounts;
     325             : 
     326           0 :       if (mounts)
     327           0 :         last_mntent = setmntent (mounts, "r");
     328             :       else
     329           0 :         last_mntent = NULL;
     330             :     }
     331             : 
     332           0 :   if (!last_mntent)
     333           0 :     return -1;
     334             : 
     335             :   for (;;)
     336           0 :     {
     337             :       int fd;
     338             :       struct mntent mnt;
     339             :       char buf[MAXPATHLEN * 3];
     340             : 
     341           0 :       if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)) == NULL)
     342           0 :         return -1;
     343             : 
     344           0 :       if (hasmntopt (&mnt, "ro")
     345           0 :           || hasmntopt (&mnt, "noexec")
     346           0 :           || access (mnt.mnt_dir, W_OK))
     347           0 :         continue;
     348             : 
     349           0 :       fd = open_temp_exec_file_dir (mnt.mnt_dir);
     350             : 
     351           0 :       if (fd != -1)
     352           0 :         return fd;
     353             :     }
     354             : }
     355             : #endif /* HAVE_MNTENT */
     356             : 
     357             : /* Instructions to look for a location to hold a temporary file that
     358             :    can be mapped in for execution.  */
     359             : static struct
     360             : {
     361             :   int (*func)(const char *);
     362             :   const char *arg;
     363             :   int repeat;
     364             : } open_temp_exec_file_opts[] = {
     365             :   { open_temp_exec_file_env, "TMPDIR", 0 },
     366             :   { open_temp_exec_file_dir, "/tmp", 0 },
     367             :   { open_temp_exec_file_dir, "/var/tmp", 0 },
     368             :   { open_temp_exec_file_dir, "/dev/shm", 0 },
     369             :   { open_temp_exec_file_env, "HOME", 0 },
     370             : #ifdef HAVE_MNTENT
     371             :   { open_temp_exec_file_mnt, "/etc/mtab", 1 },
     372             :   { open_temp_exec_file_mnt, "/proc/mounts", 1 },
     373             : #endif /* HAVE_MNTENT */
     374             : };
     375             : 
     376             : /* Current index into open_temp_exec_file_opts.  */
     377             : static int open_temp_exec_file_opts_idx = 0;
     378             : 
     379             : /* Reset a current multi-call func, then advances to the next entry.
     380             :    If we're at the last, go back to the first and return nonzero,
     381             :    otherwise return zero.  */
     382             : static int
     383           0 : open_temp_exec_file_opts_next (void)
     384             : {
     385           0 :   if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
     386           0 :     open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
     387             : 
     388           0 :   open_temp_exec_file_opts_idx++;
     389           0 :   if (open_temp_exec_file_opts_idx
     390           0 :       == (sizeof (open_temp_exec_file_opts)
     391             :           / sizeof (*open_temp_exec_file_opts)))
     392             :     {
     393           0 :       open_temp_exec_file_opts_idx = 0;
     394           0 :       return 1;
     395             :     }
     396             : 
     397           0 :   return 0;
     398             : }
     399             : 
     400             : /* Return a file descriptor of a temporary zero-sized file in a
     401             :    writable and executable filesystem.  */
     402             : static int
     403           0 : open_temp_exec_file (void)
     404             : {
     405             :   int fd;
     406             : 
     407             :   do
     408             :     {
     409           0 :       fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
     410             :         (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
     411             : 
     412           0 :       if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
     413           0 :           || fd == -1)
     414             :         {
     415           0 :           if (open_temp_exec_file_opts_next ())
     416           0 :             break;
     417             :         }
     418             :     }
     419           0 :   while (fd == -1);
     420             : 
     421           0 :   return fd;
     422             : }
     423             : 
     424             : /* Map in a chunk of memory from the temporary exec file into separate
     425             :    locations in the virtual memory address space, one writable and one
     426             :    executable.  Returns the address of the writable portion, after
     427             :    storing an offset to the corresponding executable portion at the
     428             :    last word of the requested chunk.  */
     429             : static void *
     430           0 : dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
     431             : {
     432             :   void *ptr;
     433             : 
     434           0 :   if (execfd == -1)
     435             :     {
     436           0 :       open_temp_exec_file_opts_idx = 0;
     437             :     retry_open:
     438           0 :       execfd = open_temp_exec_file ();
     439           0 :       if (execfd == -1)
     440           0 :         return MFAIL;
     441             :     }
     442             : 
     443           0 :   offset = execsize;
     444             : 
     445           0 :   if (ftruncate (execfd, offset + length))
     446           0 :     return MFAIL;
     447             : 
     448           0 :   flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
     449           0 :   flags |= MAP_SHARED;
     450             : 
     451           0 :   ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
     452             :               flags, execfd, offset);
     453           0 :   if (ptr == MFAIL)
     454             :     {
     455           0 :       if (!offset)
     456             :         {
     457           0 :           close (execfd);
     458           0 :           goto retry_open;
     459             :         }
     460           0 :       ftruncate (execfd, offset);
     461           0 :       return MFAIL;
     462             :     }
     463           0 :   else if (!offset
     464           0 :            && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
     465           0 :     open_temp_exec_file_opts_next ();
     466             : 
     467           0 :   start = mmap (start, length, prot, flags, execfd, offset);
     468             : 
     469           0 :   if (start == MFAIL)
     470             :     {
     471           0 :       munmap (ptr, length);
     472           0 :       ftruncate (execfd, offset);
     473           0 :       return start;
     474             :     }
     475             : 
     476           0 :   mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
     477             : 
     478           0 :   execsize += length;
     479             : 
     480           0 :   return start;
     481             : }
     482             : 
     483             : /* Map in a writable and executable chunk of memory if possible.
     484             :    Failing that, fall back to dlmmap_locked.  */
     485             : static void *
     486           0 : dlmmap (void *start, size_t length, int prot,
     487             :         int flags, int fd, off_t offset)
     488             : {
     489             :   void *ptr;
     490             : 
     491           0 :   assert (start == NULL && length % malloc_getpagesize == 0
     492             :           && prot == (PROT_READ | PROT_WRITE)
     493             :           && flags == (MAP_PRIVATE | MAP_ANONYMOUS)
     494             :           && fd == -1 && offset == 0);
     495             : 
     496             : #if FFI_CLOSURE_TEST
     497             :   printf ("mapping in %zi\n", length);
     498             : #endif
     499             : 
     500             :   if (execfd == -1 && is_emutramp_enabled ())
     501             :     {
     502             :       ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
     503             :       return ptr;
     504             :     }
     505             : 
     506           0 :   if (execfd == -1 && !is_selinux_enabled ())
     507             :     {
     508           0 :       ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
     509             : 
     510           0 :       if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
     511             :         /* Cool, no need to mess with separate segments.  */
     512           0 :         return ptr;
     513             : 
     514             :       /* If MREMAP_DUP is ever introduced and implemented, try mmap
     515             :          with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
     516             :          MREMAP_DUP and prot at this point.  */
     517             :     }
     518             : 
     519           0 :   if (execsize == 0 || execfd == -1)
     520             :     {
     521           0 :       pthread_mutex_lock (&open_temp_exec_file_mutex);
     522           0 :       ptr = dlmmap_locked (start, length, prot, flags, offset);
     523           0 :       pthread_mutex_unlock (&open_temp_exec_file_mutex);
     524             : 
     525           0 :       return ptr;
     526             :     }
     527             : 
     528           0 :   return dlmmap_locked (start, length, prot, flags, offset);
     529             : }
     530             : 
     531             : /* Release memory at the given address, as well as the corresponding
     532             :    executable page if it's separate.  */
     533             : static int
     534           0 : dlmunmap (void *start, size_t length)
     535             : {
     536             :   /* We don't bother decreasing execsize or truncating the file, since
     537             :      we can't quite tell whether we're unmapping the end of the file.
     538             :      We don't expect frequent deallocation anyway.  If we did, we
     539             :      could locate pages in the file by writing to the pages being
     540             :      deallocated and checking that the file contents change.
     541             :      Yuck.  */
     542           0 :   msegmentptr seg = segment_holding (gm, start);
     543             :   void *code;
     544             : 
     545             : #if FFI_CLOSURE_TEST
     546             :   printf ("unmapping %zi\n", length);
     547             : #endif
     548             : 
     549           0 :   if (seg && (code = add_segment_exec_offset (start, seg)) != start)
     550             :     {
     551           0 :       int ret = munmap (code, length);
     552           0 :       if (ret)
     553           0 :         return ret;
     554             :     }
     555             : 
     556           0 :   return munmap (start, length);
     557             : }
     558             : 
     559             : #if FFI_CLOSURE_FREE_CODE
     560             : /* Return segment holding given code address.  */
     561             : static msegmentptr
     562             : segment_holding_code (mstate m, char* addr)
     563             : {
     564             :   msegmentptr sp = &m->seg;
     565             :   for (;;) {
     566             :     if (addr >= add_segment_exec_offset (sp->base, sp)
     567             :         && addr < add_segment_exec_offset (sp->base, sp) + sp->size)
     568             :       return sp;
     569             :     if ((sp = sp->next) == 0)
     570             :       return 0;
     571             :   }
     572             : }
     573             : #endif
     574             : 
     575             : #endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
     576             : 
     577             : /* Allocate a chunk of memory with the given size.  Returns a pointer
     578             :    to the writable address, and sets *CODE to the executable
     579             :    corresponding virtual address.  */
     580             : void *
     581           0 : ffi_closure_alloc (size_t size, void **code)
     582             : {
     583             :   void *ptr;
     584             : 
     585           0 :   if (!code)
     586           0 :     return NULL;
     587             : 
     588           0 :   ptr = dlmalloc (size);
     589             : 
     590           0 :   if (ptr)
     591             :     {
     592           0 :       msegmentptr seg = segment_holding (gm, ptr);
     593             : 
     594           0 :       *code = add_segment_exec_offset (ptr, seg);
     595             :     }
     596             : 
     597           0 :   return ptr;
     598             : }
     599             : 
     600             : /* Release a chunk of memory allocated with ffi_closure_alloc.  If
     601             :    FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
     602             :    writable or the executable address given.  Otherwise, only the
     603             :    writable address can be provided here.  */
     604             : void
     605           0 : ffi_closure_free (void *ptr)
     606             : {
     607             : #if FFI_CLOSURE_FREE_CODE
     608             :   msegmentptr seg = segment_holding_code (gm, ptr);
     609             : 
     610             :   if (seg)
     611             :     ptr = sub_segment_exec_offset (ptr, seg);
     612             : #endif
     613             : 
     614           0 :   dlfree (ptr);
     615           0 : }
     616             : 
     617             : 
     618             : #if FFI_CLOSURE_TEST
     619             : /* Do some internal sanity testing to make sure allocation and
     620             :    deallocation of pages are working as intended.  */
     621             : int main ()
     622             : {
     623             :   void *p[3];
     624             : #define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
     625             : #define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
     626             :   GET (0, malloc_getpagesize / 2);
     627             :   GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
     628             :   PUT (1);
     629             :   GET (1, 2 * malloc_getpagesize);
     630             :   GET (2, malloc_getpagesize / 2);
     631             :   PUT (1);
     632             :   PUT (0);
     633             :   PUT (2);
     634             :   return 0;
     635             : }
     636             : #endif /* FFI_CLOSURE_TEST */
     637             : # else /* ! FFI_MMAP_EXEC_WRIT */
     638             : 
     639             : /* On many systems, memory returned by malloc is writable and
     640             :    executable, so just use it.  */
     641             : 
     642             : #include <stdlib.h>
     643             : 
     644             : void *
     645             : ffi_closure_alloc (size_t size, void **code)
     646             : {
     647             :   if (!code)
     648             :     return NULL;
     649             : 
     650             :   return *code = malloc (size);
     651             : }
     652             : 
     653             : void
     654             : ffi_closure_free (void *ptr)
     655             : {
     656             :   free (ptr);
     657             : }
     658             : 
     659             : # endif /* ! FFI_MMAP_EXEC_WRIT */
     660             : #endif /* FFI_CLOSURES */

Generated by: LCOV version 1.13