Ruby 2.7.0p0(2019-12-25revision647ee6f091eafcce70ffb75ddf7e121e192ab217)

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