annotate libffi/src/closures.c @ 158:494b0b89df80 default tip

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