Ruby  2.7.1p83(2020-03-31revisiona0c7c23c9cec0d0ffcba012279cd652d28ad5bf3)
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
fopen
FILE * fopen(const char *__restrict _name, const char *__restrict _type)
strchr
char * strchr(char *, char)
mkostemp
int mkostemp(char *, int)
O_CLOEXEC
#define O_CLOEXEC
Definition: dir.c:28
dlvalloc
void * dlvalloc(size_t)
Definition: dlmalloc.c:4408
EINVAL
#define EINVAL
Definition: rb_mjit_min_header-2.7.1.h:10964
ffi_common.h
PTHREAD_MUTEX_INITIALIZER
#define PTHREAD_MUTEX_INITIALIZER
Definition: rb_mjit_min_header-2.7.1.h:9219
getenv
#define getenv(name)
Definition: win32.c:73
arg
VALUE arg
Definition: rb_mjit_min_header-2.7.1.h:5601
fclose
int fclose(FILE *)
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
NULL
#define NULL
Definition: _sdbm.c:101
dlcalloc
void * dlcalloc(size_t, size_t)
Definition: dlmalloc.c:4355
sscanf
int int int int int sscanf(const char *__restrict, const char *__restrict,...) __attribute__((__format__(__scanf__
malloc_segment::next
struct malloc_segment * next
Definition: dlmalloc.c:1938
malloc_segment
Definition: dlmalloc.c:1935
EISDIR
#define EISDIR
Definition: rb_mjit_min_header-2.7.1.h:10963
strlen
size_t strlen(const char *)
off_t
__off_t off_t
Definition: rb_mjit_min_header-2.7.1.h:1317
MAXPATHLEN
#define MAXPATHLEN
Definition: dln.c:69
dlmalloc_max_footprint
#define dlmalloc_max_footprint
Definition: dlmalloc.c:666
__pthread_mutex_t
Definition: rb_mjit_min_header-2.7.1.h:1346
dlindependent_comalloc
#define dlindependent_comalloc
Definition: dlmalloc.c:668
MFAIL
#define MFAIL
Definition: dlmalloc.c:1288
malloc_segment::base
char * base
Definition: dlmalloc.c:1936
dlmalloc.c
pthread_mutex_unlock
int pthread_mutex_unlock(pthread_mutex_t *)
malloc
void * malloc(size_t) __attribute__((__malloc__)) __attribute__((__warn_unused_result__)) __attribute__((__alloc_size__(1)))
W_OK
#define W_OK
Definition: file.h:17
unlink
int unlink(const char *__path)
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
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
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4322
getline
ssize_t getline(char **, size_t *, FILE *)
f
#define f
dlfree
void dlfree(void *)
Definition: dlmalloc.c:4255
access
int access(const char *__path, int __amode)
close
int close(int __fildes)
int
__inline__ int
Definition: rb_mjit_min_header-2.7.1.h:2839
memcpy
void * memcpy(void *__restrict, const void *__restrict, size_t)
ftruncate
int ftruncate(int __fd, off_t __length)
dlindependent_calloc
#define dlindependent_calloc
Definition: dlmalloc.c:667
free
#define free(x)
Definition: dln.c:52
dlmallopt
int dlmallopt(int, int)
Definition: dlmalloc.c:4458
mkstemp
int mkstemp(char *)
errno
int errno
len
uint8_t len
Definition: escape.c:17
printf
int int int printf(const char *__restrict,...) __attribute__((__format__(__printf__
malloc_state
Definition: dlmalloc.c:2069
MAYBE_UNUSED
#define MAYBE_UNUSED
Definition: ffi_common.h:32
strncmp
int strncmp(const char *, const char *, size_t)
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
pthread_mutex_lock
int pthread_mutex_lock(pthread_mutex_t *)
malloc_segment::size
size_t size
Definition: dlmalloc.c:1937
EACCES
#define EACCES
Definition: rb_mjit_min_header-2.7.1.h:10955
main
int main(void)
Definition: closure_fn0.c:49
__sFILE
Definition: vsnprintf.c:169
name
const char * name
Definition: nkf.c:208