LCOV - code coverage report
Current view: directory - js/src/ctypes/libffi/src - closures.c (source / functions) Found Hit Coverage
Test: app.info Lines: 137 0 0.0 %
Date: 2012-04-07 Functions: 12 0 0.0 %

       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) || defined(__OS2__)
      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               0 : selinux_enabled_check (void)
     129                 : {
     130                 :   struct statfs sfs;
     131                 :   FILE *f;
     132               0 :   char *buf = NULL;
     133               0 :   size_t len = 0;
     134                 : 
     135               0 :   if (statfs ("/selinux", &sfs) >= 0
     136               0 :       && (unsigned int) sfs.f_type == 0xf97cff8cU)
     137               0 :     return 1;
     138               0 :   f = fopen ("/proc/mounts", "r");
     139               0 :   if (f == NULL)
     140               0 :     return 0;
     141               0 :   while (getline (&buf, &len, f) >= 0)
     142                 :     {
     143               0 :       char *p = strchr (buf, ' ');
     144               0 :       if (p == NULL)
     145               0 :         break;
     146               0 :       p = strchr (p + 1, ' ');
     147               0 :       if (p == NULL)
     148               0 :         break;
     149               0 :       if (strncmp (p + 1, "selinuxfs ", 10) == 0)
     150                 :         {
     151               0 :           free (buf);
     152               0 :           fclose (f);
     153               0 :           return 1;
     154                 :         }
     155                 :     }
     156               0 :   free (buf);
     157               0 :   fclose (f);
     158               0 :   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(__OS2__)) || 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(__OS2__)) || 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(__OS2__)) || 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               0 : open_temp_exec_file_name (char *name)
     225                 : {
     226               0 :   int fd = mkstemp (name);
     227                 : 
     228               0 :   if (fd != -1)
     229               0 :     unlink (name);
     230                 : 
     231               0 :   return fd;
     232                 : }
     233                 : 
     234                 : /* Open a temporary file in the named directory.  */
     235                 : static int
     236               0 : open_temp_exec_file_dir (const char *dir)
     237                 : {
     238                 :   static const char suffix[] = "/ffiXXXXXX";
     239               0 :   int lendir = strlen (dir);
     240               0 :   char *tempname = __builtin_alloca (lendir + sizeof (suffix));
     241                 : 
     242               0 :   if (!tempname)
     243               0 :     return -1;
     244                 : 
     245               0 :   memcpy (tempname, dir, lendir);
     246               0 :   memcpy (tempname + lendir, suffix, sizeof (suffix));
     247                 : 
     248               0 :   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               0 : open_temp_exec_file_env (const char *envvar)
     255                 : {
     256               0 :   const char *value = getenv (envvar);
     257                 : 
     258               0 :   if (!value)
     259               0 :     return -1;
     260                 : 
     261               0 :   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               0 : open_temp_exec_file_mnt (const char *mounts)
     271                 : {
     272                 :   static const char *last_mounts;
     273                 :   static FILE *last_mntent;
     274                 : 
     275               0 :   if (mounts != last_mounts)
     276                 :     {
     277               0 :       if (last_mntent)
     278               0 :         endmntent (last_mntent);
     279                 : 
     280               0 :       last_mounts = mounts;
     281                 : 
     282               0 :       if (mounts)
     283               0 :         last_mntent = setmntent (mounts, "r");
     284                 :       else
     285               0 :         last_mntent = NULL;
     286                 :     }
     287                 : 
     288               0 :   if (!last_mntent)
     289               0 :     return -1;
     290                 : 
     291                 :   for (;;)
     292                 :     {
     293                 :       int fd;
     294                 :       struct mntent mnt;
     295                 :       char buf[MAXPATHLEN * 3];
     296                 : 
     297               0 :       if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)))
     298               0 :         return -1;
     299                 : 
     300               0 :       if (hasmntopt (&mnt, "ro")
     301               0 :           || hasmntopt (&mnt, "noexec")
     302               0 :           || access (mnt.mnt_dir, W_OK))
     303               0 :         continue;
     304                 : 
     305               0 :       fd = open_temp_exec_file_dir (mnt.mnt_dir);
     306                 : 
     307               0 :       if (fd != -1)
     308               0 :         return fd;
     309               0 :     }
     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               0 : open_temp_exec_file_opts_next (void)
     340                 : {
     341               0 :   if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
     342               0 :     open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
     343                 : 
     344               0 :   open_temp_exec_file_opts_idx++;
     345               0 :   if (open_temp_exec_file_opts_idx
     346               0 :       == (sizeof (open_temp_exec_file_opts)
     347                 :           / sizeof (*open_temp_exec_file_opts)))
     348                 :     {
     349               0 :       open_temp_exec_file_opts_idx = 0;
     350               0 :       return 1;
     351                 :     }
     352                 : 
     353               0 :   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               0 : open_temp_exec_file (void)
     360                 : {
     361                 :   int fd;
     362                 : 
     363                 :   do
     364                 :     {
     365               0 :       fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
     366               0 :         (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
     367                 : 
     368               0 :       if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
     369               0 :           || fd == -1)
     370                 :         {
     371               0 :           if (open_temp_exec_file_opts_next ())
     372               0 :             break;
     373                 :         }
     374                 :     }
     375               0 :   while (fd == -1);
     376                 : 
     377               0 :   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               0 : dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
     387                 : {
     388                 :   void *ptr;
     389                 : 
     390               0 :   if (execfd == -1)
     391                 :     {
     392               0 :       open_temp_exec_file_opts_idx = 0;
     393                 :     retry_open:
     394               0 :       execfd = open_temp_exec_file ();
     395               0 :       if (execfd == -1)
     396               0 :         return MFAIL;
     397                 :     }
     398                 : 
     399               0 :   offset = execsize;
     400                 : 
     401               0 :   if (ftruncate (execfd, offset + length))
     402               0 :     return MFAIL;
     403                 : 
     404               0 :   flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
     405               0 :   flags |= MAP_SHARED;
     406                 : 
     407               0 :   ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
     408                 :               flags, execfd, offset);
     409               0 :   if (ptr == MFAIL)
     410                 :     {
     411               0 :       if (!offset)
     412                 :         {
     413               0 :           close (execfd);
     414               0 :           goto retry_open;
     415                 :         }
     416               0 :       ftruncate (execfd, offset);
     417               0 :       return MFAIL;
     418                 :     }
     419               0 :   else if (!offset
     420               0 :            && open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
     421               0 :     open_temp_exec_file_opts_next ();
     422                 : 
     423               0 :   start = mmap (start, length, prot, flags, execfd, offset);
     424                 : 
     425               0 :   if (start == MFAIL)
     426                 :     {
     427               0 :       munmap (ptr, length);
     428               0 :       ftruncate (execfd, offset);
     429               0 :       return start;
     430                 :     }
     431                 : 
     432               0 :   mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
     433                 : 
     434               0 :   execsize += length;
     435                 : 
     436               0 :   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               0 : 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               0 :   if (execfd == -1 && !is_selinux_enabled ())
     457                 :     {
     458               0 :       ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
     459                 : 
     460               0 :       if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
     461                 :         /* Cool, no need to mess with separate segments.  */
     462               0 :         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               0 :   if (execsize == 0 || execfd == -1)
     470                 :     {
     471               0 :       pthread_mutex_lock (&open_temp_exec_file_mutex);
     472               0 :       ptr = dlmmap_locked (start, length, prot, flags, offset);
     473               0 :       pthread_mutex_unlock (&open_temp_exec_file_mutex);
     474                 : 
     475               0 :       return ptr;
     476                 :     }
     477                 : 
     478               0 :   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               0 : 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               0 :   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               0 :   if (seg && (code = add_segment_exec_offset (start, seg)) != start)
     500                 :     {
     501               0 :       int ret = munmap (code, length);
     502               0 :       if (ret)
     503               0 :         return ret;
     504                 :     }
     505                 : 
     506               0 :   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(__OS2__)) || 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               0 : ffi_closure_alloc (size_t size, void **code)
     532                 : {
     533                 :   void *ptr;
     534                 : 
     535               0 :   if (!code)
     536               0 :     return NULL;
     537                 : 
     538               0 :   ptr = dlmalloc (size);
     539                 : 
     540               0 :   if (ptr)
     541                 :     {
     542               0 :       msegmentptr seg = segment_holding (gm, ptr);
     543                 : 
     544               0 :       *code = add_segment_exec_offset (ptr, seg);
     545                 :     }
     546                 : 
     547               0 :   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               0 : 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               0 :   dlfree (ptr);
     565               0 : }
     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 */

Generated by: LCOV version 1.7