📄 openbsd_malloc_linux.c
字号:
/* Version 1.83 for Linux.
* Compilation: gcc -shared -fPIC -O2 OpenBSD_malloc_Linux.c -o malloc.so
* Launching: LD_PRELOAD=/path/to/malloc.so firefox
*/
/* $OpenBSD: malloc.c,v 1.83 2006/05/14 19:53:40 otto Exp $ */
/*
* ----------------------------------------------------------------------------
* "THE BEER-WARE LICENSE" (Revision 42):
* <phk@FreeBSD.ORG> wrote this file. As long as you retain this notice you
* can do whatever you want with this stuff. If we meet some day, and you think
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*/
/*
* Defining MALLOC_EXTRA_SANITY will enable extra checks which are
* related to internal conditions and consistency in malloc.c. This has
* a noticeable runtime performance hit, and generally will not do you
* any good unless you fiddle with the internals of malloc or want
* to catch random pointer corruption as early as possible.
*/
#ifndef MALLOC_EXTRA_SANITY
#undef MALLOC_EXTRA_SANITY
#endif
/*
* Defining MALLOC_STATS will enable you to call malloc_dump() and set
* the [dD] options in the MALLOC_OPTIONS environment variable.
* It has no run-time performance hit, but does pull in stdio...
*/
#ifndef MALLOC_STATS
#undef MALLOC_STATS
#endif
/*
* What to use for Junk. This is the byte value we use to fill with
* when the 'J' option is enabled.
*/
#define SOME_JUNK 0xd0 /* as in "Duh" :-) */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <limits.h>
#include <errno.h>
#include <err.h>
/* For SIZE_T_MAX */
#include "torint.h"
//#include "thread_private.h"
/*
* The basic parameters you can tweak.
*
* malloc_pageshift pagesize = 1 << malloc_pageshift
* It's probably best if this is the native
* page size, but it shouldn't have to be.
*
* malloc_minsize minimum size of an allocation in bytes.
* If this is too small it's too much work
* to manage them. This is also the smallest
* unit of alignment used for the storage
* returned by malloc/realloc.
*
*/
static int align = 0;
static size_t g_alignment = 0;
extern int __libc_enable_secure;
static int issetugid(void)
{
if (__libc_enable_secure) return 1;
if (getuid() != geteuid()) return 1;
if (getgid() != getegid()) return 1;
return 0;
}
#define PGSHIFT 12
#define MADV_FREE MADV_DONTNEED
#include <pthread.h>
static pthread_mutex_t gen_mutex = PTHREAD_MUTEX_INITIALIZER;
#define _MALLOC_LOCK_INIT() {;}
#define _MALLOC_LOCK() {pthread_mutex_lock(&gen_mutex);}
#define _MALLOC_UNLOCK() {pthread_mutex_unlock(&gen_mutex);}
#if defined(__sparc__) || defined(__alpha__)
#define malloc_pageshift 13U
#endif
#if defined(__ia64__)
#define malloc_pageshift 14U
#endif
#ifndef malloc_pageshift
#define malloc_pageshift (PGSHIFT)
#endif
/*
* No user serviceable parts behind this point.
*
* This structure describes a page worth of chunks.
*/
struct pginfo {
struct pginfo *next; /* next on the free list */
void *page; /* Pointer to the page */
u_short size; /* size of this page's chunks */
u_short shift; /* How far to shift for this size chunks */
u_short free; /* How many free chunks */
u_short total; /* How many chunk */
u_long bits[1];/* Which chunks are free */
};
/* How many bits per u_long in the bitmap */
#define MALLOC_BITS (NBBY * sizeof(u_long))
/*
* This structure describes a number of free pages.
*/
struct pgfree {
struct pgfree *next; /* next run of free pages */
struct pgfree *prev; /* prev run of free pages */
void *page; /* pointer to free pages */
void *pdir; /* pointer to the base page's dir */
size_t size; /* number of bytes free */
};
/*
* Magic values to put in the page_directory
*/
#define MALLOC_NOT_MINE ((struct pginfo*) 0)
#define MALLOC_FREE ((struct pginfo*) 1)
#define MALLOC_FIRST ((struct pginfo*) 2)
#define MALLOC_FOLLOW ((struct pginfo*) 3)
#define MALLOC_MAGIC ((struct pginfo*) 4)
#ifndef malloc_minsize
#define malloc_minsize 16UL
#endif
#if !defined(malloc_pagesize)
#define malloc_pagesize (1UL<<malloc_pageshift)
#endif
#if ((1UL<<malloc_pageshift) != malloc_pagesize)
#error "(1UL<<malloc_pageshift) != malloc_pagesize"
#endif
#ifndef malloc_maxsize
#define malloc_maxsize ((malloc_pagesize)>>1)
#endif
/* A mask for the offset inside a page. */
#define malloc_pagemask ((malloc_pagesize)-1)
#define pageround(foo) (((foo) + (malloc_pagemask)) & ~malloc_pagemask)
#define ptr2index(foo) (((u_long)(foo) >> malloc_pageshift)+malloc_pageshift)
#define index2ptr(idx) ((void*)(((idx)-malloc_pageshift)<<malloc_pageshift))
/* Set when initialization has been done */
static unsigned int malloc_started;
/* Number of free pages we cache */
static unsigned int malloc_cache = 16;
/* Structure used for linking discrete directory pages. */
struct pdinfo {
struct pginfo **base;
struct pdinfo *prev;
struct pdinfo *next;
u_long dirnum;
};
static struct pdinfo *last_dir; /* Caches to the last and previous */
static struct pdinfo *prev_dir; /* referenced directory pages. */
static size_t pdi_off;
static u_long pdi_mod;
#define PD_IDX(num) ((num) / (malloc_pagesize/sizeof(struct pginfo *)))
#define PD_OFF(num) ((num) & ((malloc_pagesize/sizeof(struct pginfo *))-1))
#define PI_IDX(index) ((index) / pdi_mod)
#define PI_OFF(index) ((index) % pdi_mod)
/* The last index in the page directory we care about */
static u_long last_index;
/* Pointer to page directory. Allocated "as if with" malloc */
static struct pginfo **page_dir;
/* Free pages line up here */
static struct pgfree free_list;
/* Abort(), user doesn't handle problems. */
static int malloc_abort = 2;
/* Are we trying to die ? */
static int suicide;
#ifdef MALLOC_STATS
/* dump statistics */
static int malloc_stats;
#endif
/* avoid outputting warnings? */
static int malloc_silent;
/* always realloc ? */
static int malloc_realloc;
/* mprotect free pages PROT_NONE? */
static int malloc_freeprot;
/* use guard pages after allocations? */
static size_t malloc_guard = 0;
static size_t malloc_guarded;
/* align pointers to end of page? */
static int malloc_ptrguard;
static int malloc_hint = 1;
/* xmalloc behaviour ? */
static int malloc_xmalloc;
/* zero fill ? */
static int malloc_zero;
/* junk fill ? */
static int malloc_junk;
#ifdef __FreeBSD__
/* utrace ? */
static int malloc_utrace;
struct ut {
void *p;
size_t s;
void *r;
};
void utrace(struct ut *, int);
#define UTRACE(a, b, c) \
if (malloc_utrace) \
{struct ut u; u.p=a; u.s = b; u.r=c; utrace(&u, sizeof u);}
#else /* !__FreeBSD__ */
#define UTRACE(a,b,c)
#endif
/* Status of malloc. */
static int malloc_active;
/* Allocated memory. */
static size_t malloc_used;
/* My last break. */
static caddr_t malloc_brk;
/* One location cache for free-list holders. */
static struct pgfree *px;
/* Compile-time options. */
char *malloc_options;
/* Name of the current public function. */
static char *malloc_func;
#define MMAP(size) \
mmap((void *)0, (size), PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, \
-1, (off_t)0)
/*
* Necessary function declarations.
*/
static void *imalloc(size_t size);
static void ifree(void *ptr);
static void *irealloc(void *ptr, size_t size);
static void *malloc_bytes(size_t size);
/*
* Function for page directory lookup.
*/
static int
pdir_lookup(u_long index, struct pdinfo ** pdi)
{
struct pdinfo *spi;
u_long pidx = PI_IDX(index);
if (last_dir != NULL && PD_IDX(last_dir->dirnum) == pidx)
*pdi = last_dir;
else if (prev_dir != NULL && PD_IDX(prev_dir->dirnum) == pidx)
*pdi = prev_dir;
else if (last_dir != NULL && prev_dir != NULL) {
if ((PD_IDX(last_dir->dirnum) > pidx) ?
(PD_IDX(last_dir->dirnum) - pidx) :
(pidx - PD_IDX(last_dir->dirnum))
< (PD_IDX(prev_dir->dirnum) > pidx) ?
(PD_IDX(prev_dir->dirnum) - pidx) :
(pidx - PD_IDX(prev_dir->dirnum)))
*pdi = last_dir;
else
*pdi = prev_dir;
if (PD_IDX((*pdi)->dirnum) > pidx) {
for (spi = (*pdi)->prev;
spi != NULL && PD_IDX(spi->dirnum) > pidx;
spi = spi->prev)
*pdi = spi;
if (spi != NULL)
*pdi = spi;
} else
for (spi = (*pdi)->next;
spi != NULL && PD_IDX(spi->dirnum) <= pidx;
spi = spi->next)
*pdi = spi;
} else {
*pdi = (struct pdinfo *) ((caddr_t) page_dir + pdi_off);
for (spi = *pdi;
spi != NULL && PD_IDX(spi->dirnum) <= pidx;
spi = spi->next)
*pdi = spi;
}
return ((PD_IDX((*pdi)->dirnum) == pidx) ? 0 :
(PD_IDX((*pdi)->dirnum) > pidx) ? 1 : -1);
}
#ifdef MALLOC_STATS
void
malloc_dump(int fd)
{
char buf[1024];
struct pginfo **pd;
struct pgfree *pf;
struct pdinfo *pi;
u_long j;
pd = page_dir;
pi = (struct pdinfo *) ((caddr_t) pd + pdi_off);
/* print out all the pages */
for (j = 0; j <= last_index;) {
snprintf(buf, sizeof buf, "%08lx %5lu ", j << malloc_pageshift, j);
write(fd, buf, strlen(buf));
if (pd[PI_OFF(j)] == MALLOC_NOT_MINE) {
for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_NOT_MINE;) {
if (!PI_OFF(++j)) {
if ((pi = pi->next) == NULL ||
PD_IDX(pi->dirnum) != PI_IDX(j))
break;
pd = pi->base;
j += pdi_mod;
}
}
j--;
snprintf(buf, sizeof buf, ".. %5lu not mine\n", j);
write(fd, buf, strlen(buf));
} else if (pd[PI_OFF(j)] == MALLOC_FREE) {
for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FREE;) {
if (!PI_OFF(++j)) {
if ((pi = pi->next) == NULL ||
PD_IDX(pi->dirnum) != PI_IDX(j))
break;
pd = pi->base;
j += pdi_mod;
}
}
j--;
snprintf(buf, sizeof buf, ".. %5lu free\n", j);
write(fd, buf, strlen(buf));
} else if (pd[PI_OFF(j)] == MALLOC_FIRST) {
for (j++; j <= last_index && pd[PI_OFF(j)] == MALLOC_FOLLOW;) {
if (!PI_OFF(++j)) {
if ((pi = pi->next) == NULL ||
PD_IDX(pi->dirnum) != PI_IDX(j))
break;
pd = pi->base;
j += pdi_mod;
}
}
j--;
snprintf(buf, sizeof buf, ".. %5lu in use\n", j);
write(fd, buf, strlen(buf));
} else if (pd[PI_OFF(j)] < MALLOC_MAGIC) {
snprintf(buf, sizeof buf, "(%p)\n", pd[PI_OFF(j)]);
write(fd, buf, strlen(buf));
} else {
snprintf(buf, sizeof buf, "%p %d (of %d) x %d @ %p --> %p\n",
pd[PI_OFF(j)], pd[PI_OFF(j)]->free,
pd[PI_OFF(j)]->total, pd[PI_OFF(j)]->size,
pd[PI_OFF(j)]->page, pd[PI_OFF(j)]->next);
write(fd, buf, strlen(buf));
}
if (!PI_OFF(++j)) {
if ((pi = pi->next) == NULL)
break;
pd = pi->base;
j += (1 + PD_IDX(pi->dirnum) - PI_IDX(j)) * pdi_mod;
}
}
for (pf = free_list.next; pf; pf = pf->next) {
snprintf(buf, sizeof buf, "Free: @%p [%p...%p[ %ld ->%p <-%p\n",
pf, pf->page, (char *)pf->page + pf->size,
pf->size, pf->prev, pf->next);
write(fd, buf, strlen(buf));
if (pf == pf->next) {
snprintf(buf, sizeof buf, "Free_list loops\n");
write(fd, buf, strlen(buf));
break;
}
}
/* print out various info */
snprintf(buf, sizeof buf, "Minsize\t%lu\n", malloc_minsize);
write(fd, buf, strlen(buf));
snprintf(buf, sizeof buf, "Maxsize\t%lu\n", malloc_maxsize);
write(fd, buf, strlen(buf));
snprintf(buf, sizeof buf, "Pagesize\t%lu\n", malloc_pagesize);
write(fd, buf, strlen(buf));
snprintf(buf, sizeof buf, "Pageshift\t%u\n", malloc_pageshift);
write(fd, buf, strlen(buf));
snprintf(buf, sizeof buf, "In use\t%lu\n", (u_long) malloc_used);
write(fd, buf, strlen(buf));
snprintf(buf, sizeof buf, "Guarded\t%lu\n", (u_long) malloc_guarded);
write(fd, buf, strlen(buf));
}
#endif /* MALLOC_STATS */
extern char *__progname;
static void
wrterror(char *p)
{
char *q = " error: ";
struct iovec iov[5];
iov[0].iov_base = __progname;
iov[0].iov_len = strlen(__progname);
iov[1].iov_base = malloc_func;
iov[1].iov_len = strlen(malloc_func);
iov[2].iov_base = q;
iov[2].iov_len = strlen(q);
iov[3].iov_base = p;
iov[3].iov_len = strlen(p);
iov[4].iov_base = "\n";
iov[4].iov_len = 1;
writev(STDERR_FILENO, iov, 5);
suicide = 1;
#ifdef MALLOC_STATS
if (malloc_stats)
malloc_dump(STDERR_FILENO);
#endif /* MALLOC_STATS */
malloc_active--;
if (malloc_abort)
abort();
}
static void
wrtwarning(char *p)
{
char *q = " warning: ";
struct iovec iov[5];
if (malloc_abort)
wrterror(p);
else if (malloc_silent)
return;
iov[0].iov_base = __progname;
iov[0].iov_len = strlen(__progname);
iov[1].iov_base = malloc_func;
iov[1].iov_len = strlen(malloc_func);
iov[2].iov_base = q;
iov[2].iov_len = strlen(q);
iov[3].iov_base = p;
iov[3].iov_len = strlen(p);
iov[4].iov_base = "\n";
iov[4].iov_len = 1;
writev(STDERR_FILENO, iov, 5);
}
#ifdef MALLOC_STATS
static void
malloc_exit(void)
{
char *q = "malloc() warning: Couldn't dump stats\n";
int save_errno = errno, fd;
fd = open("malloc.out", O_RDWR|O_APPEND);
if (fd != -1) {
malloc_dump(fd);
close(fd);
} else
write(STDERR_FILENO, q, strlen(q));
errno = save_errno;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -