~ubuntu-branches/ubuntu/trusty/python3.4/trusty-proposed

« back to all changes in this revision

Viewing changes to Modules/_ctypes/libffi/src/closures.c

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-11-25 09:44:27 UTC
  • Revision ID: package-import@ubuntu.com-20131125094427-lzxj8ap5w01lmo7f
Tags: upstream-3.4~b1
ImportĀ upstreamĀ versionĀ 3.4~b1

Show diffs side-by-side

added added

removed removed

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