~ubuntu-branches/ubuntu/saucy/mozjs17/saucy

« back to all changes in this revision

Viewing changes to js/src/ctypes/libffi/src/closures.c

  • Committer: Package Import Robot
  • Author(s): Rico Tzschichholz
  • Date: 2013-05-25 12:24:23 UTC
  • Revision ID: package-import@ubuntu.com-20130525122423-zmxucrhtensw90xy
Tags: upstream-17.0.0
ImportĀ upstreamĀ versionĀ 17.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
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(__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
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(__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
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 */