📄 openbsd_malloc_linux.c
字号:
#endif /* MALLOC_STATS */
/*
* Allocate aligned mmaped chunk
*/
static void *MMAP_A(size_t pages, size_t alignment)
{
void *j;
if (pages%malloc_pagesize != 0)
pages = pages - pages%malloc_pagesize + malloc_pagesize;
size_t first_size = pages + alignment - malloc_pagesize;
void *p = MMAP(first_size);
size_t rest = ((size_t)p) % alignment;
j = (rest == 0) ? p : (void*) ((size_t)p + alignment - rest);
size_t begin = (size_t)j - (size_t)p;
if (begin != 0) munmap(p, begin);
size_t end = (size_t)p + first_size - ((size_t)j + pages);
if(end != 0) munmap( (void*) ((size_t)j + pages), end);
return j;
}
/*
* Allocate a number of pages from the OS
*/
static void *
map_pages(size_t pages)
{
struct pdinfo *pi, *spi;
struct pginfo **pd;
u_long idx, pidx, lidx;
caddr_t result, tail;
u_long index, lindex;
void *pdregion = NULL;
size_t dirs, cnt;
pages <<= malloc_pageshift;
if (!align)
result = MMAP(pages + malloc_guard);
else {
result = MMAP_A(pages + malloc_guard, g_alignment);
}
if (result == MAP_FAILED) {
#ifdef MALLOC_EXTRA_SANITY
wrtwarning("(ES): map_pages fails");
#endif /* MALLOC_EXTRA_SANITY */
errno = ENOMEM;
return (NULL);
}
index = ptr2index(result);
tail = result + pages + malloc_guard;
lindex = ptr2index(tail) - 1;
if (malloc_guard)
mprotect(result + pages, malloc_guard, PROT_NONE);
pidx = PI_IDX(index);
lidx = PI_IDX(lindex);
if (tail > malloc_brk) {
malloc_brk = tail;
last_index = lindex;
}
dirs = lidx - pidx;
/* Insert directory pages, if needed. */
if (pdir_lookup(index, &pi) != 0)
dirs++;
if (dirs > 0) {
pdregion = MMAP(malloc_pagesize * dirs);
if (pdregion == MAP_FAILED) {
munmap(result, tail - result);
#ifdef MALLOC_EXTRA_SANITY
wrtwarning("(ES): map_pages fails");
#endif
errno = ENOMEM;
return (NULL);
}
}
cnt = 0;
for (idx = pidx, spi = pi; idx <= lidx; idx++) {
if (pi == NULL || PD_IDX(pi->dirnum) != idx) {
pd = (struct pginfo **)((char *)pdregion +
cnt * malloc_pagesize);
cnt++;
memset(pd, 0, malloc_pagesize);
pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
pi->base = pd;
pi->prev = spi;
pi->next = spi->next;
pi->dirnum = idx * (malloc_pagesize /
sizeof(struct pginfo *));
if (spi->next != NULL)
spi->next->prev = pi;
spi->next = pi;
}
if (idx > pidx && idx < lidx) {
pi->dirnum += pdi_mod;
} else if (idx == pidx) {
if (pidx == lidx) {
pi->dirnum += (u_long)(tail - result) >>
malloc_pageshift;
} else {
pi->dirnum += pdi_mod - PI_OFF(index);
}
} else {
pi->dirnum += PI_OFF(ptr2index(tail - 1)) + 1;
}
#ifdef MALLOC_EXTRA_SANITY
if (PD_OFF(pi->dirnum) > pdi_mod || PD_IDX(pi->dirnum) > idx) {
wrterror("(ES): pages directory overflow");
errno = EFAULT;
return (NULL);
}
#endif /* MALLOC_EXTRA_SANITY */
if (idx == pidx && pi != last_dir) {
prev_dir = last_dir;
last_dir = pi;
}
spi = pi;
pi = spi->next;
}
#ifdef MALLOC_EXTRA_SANITY
if (cnt > dirs)
wrtwarning("(ES): cnt > dirs");
#endif /* MALLOC_EXTRA_SANITY */
if (cnt < dirs)
munmap((char *)pdregion + cnt * malloc_pagesize,
(dirs - cnt) * malloc_pagesize);
return (result);
}
/*
* Initialize the world
*/
static void
malloc_init(void)
{
char *p, b[64];
int i, j, save_errno = errno;
_MALLOC_LOCK_INIT();
#ifdef MALLOC_EXTRA_SANITY
malloc_junk = 1;
#endif /* MALLOC_EXTRA_SANITY */
for (i = 0; i < 3; i++) {
switch (i) {
case 0:
j = readlink("/etc/malloc.conf", b, sizeof b - 1);
if (j <= 0)
continue;
b[j] = '\0';
p = b;
break;
case 1:
if (issetugid() == 0)
p = getenv("MALLOC_OPTIONS");
else
continue;
break;
case 2:
p = malloc_options;
break;
default:
p = NULL;
}
for (; p != NULL && *p != '\0'; p++) {
switch (*p) {
case '>':
malloc_cache <<= 1;
break;
case '<':
malloc_cache >>= 1;
break;
case 'a':
malloc_abort = 0;
break;
case 'A':
malloc_abort = 1;
break;
#ifdef MALLOC_STATS
case 'd':
malloc_stats = 0;
break;
case 'D':
malloc_stats = 1;
break;
#endif /* MALLOC_STATS */
case 'f':
malloc_freeprot = 0;
break;
case 'F':
malloc_freeprot = 1;
break;
case 'g':
malloc_guard = 0;
break;
case 'G':
malloc_guard = malloc_pagesize;
break;
case 'h':
malloc_hint = 0;
break;
case 'H':
malloc_hint = 1;
break;
case 'j':
malloc_junk = 0;
break;
case 'J':
malloc_junk = 1;
break;
case 'n':
malloc_silent = 0;
break;
case 'N':
malloc_silent = 1;
break;
case 'p':
malloc_ptrguard = 0;
break;
case 'P':
malloc_ptrguard = 1;
break;
case 'r':
malloc_realloc = 0;
break;
case 'R':
malloc_realloc = 1;
break;
#ifdef __FreeBSD__
case 'u':
malloc_utrace = 0;
break;
case 'U':
malloc_utrace = 1;
break;
#endif /* __FreeBSD__ */
case 'x':
malloc_xmalloc = 0;
break;
case 'X':
malloc_xmalloc = 1;
break;
case 'z':
malloc_zero = 0;
break;
case 'Z':
malloc_zero = 1;
break;
default:
j = malloc_abort;
malloc_abort = 0;
wrtwarning("unknown char in MALLOC_OPTIONS");
malloc_abort = j;
break;
}
}
}
UTRACE(0, 0, 0);
/*
* We want junk in the entire allocation, and zero only in the part
* the user asked for.
*/
if (malloc_zero)
malloc_junk = 1;
#ifdef MALLOC_STATS
if (malloc_stats && (atexit(malloc_exit) == -1))
wrtwarning("atexit(2) failed."
" Will not be able to dump malloc stats on exit");
#endif /* MALLOC_STATS */
if (malloc_pagesize != getpagesize()) {
wrterror("malloc() replacement compiled with a different "
"page size from what we're running with. Failing.");
errno = ENOMEM;
return;
}
/* Allocate one page for the page directory. */
page_dir = (struct pginfo **)MMAP(malloc_pagesize);
if (page_dir == MAP_FAILED) {
wrterror("mmap(2) failed, check limits");
errno = ENOMEM;
return;
}
pdi_off = (malloc_pagesize - sizeof(struct pdinfo)) & ~(malloc_minsize - 1);
pdi_mod = pdi_off / sizeof(struct pginfo *);
last_dir = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
last_dir->base = page_dir;
last_dir->prev = last_dir->next = NULL;
last_dir->dirnum = malloc_pageshift;
/* Been here, done that. */
malloc_started++;
/* Recalculate the cache size in bytes, and make sure it's nonzero. */
if (!malloc_cache)
malloc_cache++;
malloc_cache <<= malloc_pageshift;
errno = save_errno;
}
/*
* Allocate a number of complete pages
*/
static void *
malloc_pages(size_t size)
{
void *p, *delay_free = NULL, *tp;
int i;
struct pginfo **pd;
struct pdinfo *pi;
u_long pidx, index;
struct pgfree *pf;
size = pageround(size) + malloc_guard;
p = NULL;
/* Look for free pages before asking for more */
if (!align)
for (pf = free_list.next; pf; pf = pf->next) {
#ifdef MALLOC_EXTRA_SANITY
if (pf->size & malloc_pagemask) {
wrterror("(ES): junk length entry on free_list");
errno = EFAULT;
return (NULL);
}
if (!pf->size) {
wrterror("(ES): zero length entry on free_list");
errno = EFAULT;
return (NULL);
}
if (pf->page > (pf->page + pf->size)) {
wrterror("(ES): sick entry on free_list");
errno = EFAULT;
return (NULL);
}
if ((pi = pf->pdir) == NULL) {
wrterror("(ES): invalid page directory on free-list");
errno = EFAULT;
return (NULL);
}
if ((pidx = PI_IDX(ptr2index(pf->page))) != PD_IDX(pi->dirnum)) {
wrterror("(ES): directory index mismatch on free-list");
errno = EFAULT;
return (NULL);
}
pd = pi->base;
if (pd[PI_OFF(ptr2index(pf->page))] != MALLOC_FREE) {
wrterror("(ES): non-free first page on free-list");
errno = EFAULT;
return (NULL);
}
pidx = PI_IDX(ptr2index((pf->page) + (pf->size)) - 1);
for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
pi = pi->next)
;
if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
wrterror("(ES): last page not referenced in page directory");
errno = EFAULT;
return (NULL);
}
pd = pi->base;
if (pd[PI_OFF(ptr2index((pf->page) + (pf->size)) - 1)] != MALLOC_FREE) {
wrterror("(ES): non-free last page on free-list");
errno = EFAULT;
return (NULL);
}
#endif /* MALLOC_EXTRA_SANITY */
if (pf->size < size)
continue;
if (pf->size == size) {
p = pf->page;
pi = pf->pdir;
if (pf->next != NULL)
pf->next->prev = pf->prev;
pf->prev->next = pf->next;
delay_free = pf;
break;
}
p = pf->page;
pf->page = (char *) pf->page + size;
pf->size -= size;
pidx = PI_IDX(ptr2index(pf->page));
for (pi = pf->pdir; pi != NULL && PD_IDX(pi->dirnum) < pidx;
pi = pi->next)
;
if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
wrterror("(ES): hole in directories");
errno = EFAULT;
return (NULL);
}
tp = pf->pdir;
pf->pdir = pi;
pi = tp;
break;
}
size -= malloc_guard;
#ifdef MALLOC_EXTRA_SANITY
if (p != NULL && pi != NULL) {
pidx = PD_IDX(pi->dirnum);
pd = pi->base;
}
if (p != NULL && pd[PI_OFF(ptr2index(p))] != MALLOC_FREE) {
wrterror("(ES): allocated non-free page on free-list");
errno = EFAULT;
return (NULL);
}
#endif /* MALLOC_EXTRA_SANITY */
if (p != NULL && (malloc_guard || malloc_freeprot))
mprotect(p, size, PROT_READ | PROT_WRITE);
size >>= malloc_pageshift;
/* Map new pages */
if (p == NULL)
p = map_pages(size);
if (p != NULL) {
index = ptr2index(p);
pidx = PI_IDX(index);
pdir_lookup(index, &pi);
#ifdef MALLOC_EXTRA_SANITY
if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
wrterror("(ES): mapped pages not found in directory");
errno = EFAULT;
return (NULL);
}
#endif /* MALLOC_EXTRA_SANITY */
if (pi != last_dir) {
prev_dir = last_dir;
last_dir = pi;
}
pd = pi->base;
pd[PI_OFF(index)] = MALLOC_FIRST;
for (i = 1; i < size; i++) {
if (!PI_OFF(index + i)) {
pidx++;
pi = pi->next;
#ifdef MALLOC_EXTRA_SANITY
if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
wrterror("(ES): hole in mapped pages directory");
errno = EFAULT;
return (NULL);
}
#endif /* MALLOC_EXTRA_SANITY */
pd = pi->base;
}
pd[PI_OFF(index + i)] = MALLOC_FOLLOW;
}
if (malloc_guard) {
if (!PI_OFF(index + i)) {
pidx++;
pi = pi->next;
#ifdef MALLOC_EXTRA_SANITY
if (pi == NULL || PD_IDX(pi->dirnum) != pidx) {
wrterror("(ES): hole in mapped pages directory");
errno = EFAULT;
return (NULL);
}
#endif /* MALLOC_EXTRA_SANITY */
pd = pi->base;
}
pd[PI_OFF(index + i)] = MALLOC_FIRST;
}
malloc_used += size << malloc_pageshift;
malloc_guarded += malloc_guard;
if (malloc_junk)
memset(p, SOME_JUNK, size << malloc_pageshift);
}
if (delay_free) {
if (px == NULL)
px = delay_free;
else
ifree(delay_free);
}
return (p);
}
/*
* Allocate a page of fragments
*/
static __inline__ int
malloc_make_chunks(int bits)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -