⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 efence.c

📁 网络时间协议NTP 源码 版本v4.2.0b 该源码用于linux平台下
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * Electric Fence - Red-Zone memory allocator. * Bruce Perens, 1988, 1993 *  * This is a special version of malloc() and company for debugging software * that is suspected of overrunning or underrunning the boundaries of a * malloc buffer, or touching free memory. * * It arranges for each malloc buffer to be followed (or preceded) * in the address space by an inaccessable virtual memory page, * and for free memory to be inaccessable. If software touches the * inaccessable page, it will get an immediate segmentation * fault. It is then trivial to uncover the offending code using a debugger. * * An advantage of this product over most malloc debuggers is that this one * detects reading out of bounds as well as writing, and this one stops on * the exact instruction that causes the error, rather than waiting until the * next boundary check. * * There is one product that debugs malloc buffer overruns * better than Electric Fence: "Purify" from Purify Systems, and that's only * a small part of what Purify does. I'm not affiliated with Purify, I just * respect a job well done. * * This version of malloc() should not be linked into production software, * since it tremendously increases the time and memory overhead of malloc(). * Each malloc buffer will consume a minimum of two virtual memory pages, * this is 16 kilobytes on many systems. On some systems it will be necessary * to increase the amount of swap space in order to debug large programs that * perform lots of allocation, because of the per-buffer overhead. */#include "efence.h"#include <stdlib.h>#include <unistd.h>#include <memory.h>#include <string.h>#ifdef	malloc#undef	malloc#endif#ifdef	calloc#undef	calloc#endifstatic const char	version[] = "\n  Electric Fence 2.0.5" " Copyright (C) 1987-1995 Bruce Perens.\n";/* * MEMORY_CREATION_SIZE is the amount of memory to get from the operating * system at one time. We'll break that memory down into smaller pieces for * malloc buffers. One megabyte is probably a good value. */#define			MEMORY_CREATION_SIZE	1024 * 1024/* * Enum Mode indicates the status of a malloc buffer. */enum _Mode {	NOT_IN_USE = 0,	/* Available to represent a malloc buffer. */	FREE,		/* A free buffer. */	ALLOCATED,	/* A buffer that is in use. */	PROTECTED,	/* A freed buffer that can not be allocated again. */	INTERNAL_USE	/* A buffer used internally by malloc(). */};typedef enum _Mode	Mode;/* * Struct Slot contains all of the information about a malloc buffer except * for the contents of its memory. */struct _Slot {	void *		userAddress;	void *		internalAddress;	size_t		userSize;	size_t		internalSize;	Mode		mode;};typedef struct _Slot	Slot;/* * EF_ALIGNMENT is a global variable used to control the default alignment * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps * so that its name matches the name of the environment variable that is used * to set it. This gives the programmer one less name to remember. * If the value is -1, it will be set from the environment or sizeof(int) * at run time. */int		EF_ALIGNMENT = -1;/* * EF_PROTECT_FREE is a global variable used to control the disposition of * memory that is released using free(). It is all-caps so that its name * matches the name of the environment variable that is used to set it. * If its value is greater non-zero, memory released by free is made * inaccessable and never allocated again. Any software that touches free * memory will then get a segmentation fault. If its value is zero, freed * memory will be available for reallocation, but will still be inaccessable * until it is reallocated. * If the value is -1, it will be set from the environment or to 0 at run-time. */int		EF_PROTECT_FREE = -1;/* * EF_PROTECT_BELOW is used to modify the behavior of the allocator. When * its value is non-zero, the allocator will place an inaccessable page * immediately _before_ the malloc buffer in the address space, instead * of _after_ it. Use this to detect malloc buffer under-runs, rather than * over-runs. It won't detect both at the same time, so you should test your * software twice, once with this value clear, and once with it set. * If the value is -1, it will be set from the environment or to zero at * run-time */int		EF_PROTECT_BELOW = -1;/* * EF_ALLOW_MALLOC_0 is set if Electric Fence is to allow malloc(0). I * trap malloc(0) by default because it is a common source of bugs. */int		EF_ALLOW_MALLOC_0 = -1;/* * allocationList points to the array of slot structures used to manage the * malloc arena. */static Slot *		allocationList = 0;/* * allocationListSize is the size of the allocation list. This will always * be a multiple of the page size. */static size_t		allocationListSize = 0;/* * slotCount is the number of Slot structures in allocationList. */static size_t		slotCount = 0;/* * unUsedSlots is the number of Slot structures that are currently available * to represent new malloc buffers. When this number gets too low, we will * create new slots. */static size_t		unUsedSlots = 0;/* * slotsPerPage is the number of slot structures that fit in a virtual * memory page. */static size_t		slotsPerPage = 0;/* * internalUse is set when allocating and freeing the allocatior-internal * data structures. */static int		internalUse = 0;/* * noAllocationListProtection is set to tell malloc() and free() not to * manipulate the protection of the allocation list. This is only set in * realloc(), which does it to save on slow system calls, and in * allocateMoreSlots(), which does it because it changes the allocation list. */static int		noAllocationListProtection = 0;/* * bytesPerPage is set at run-time to the number of bytes per virtual-memory * page, as returned by Page_Size(). */static size_t		bytesPerPage = 0;/* * internalError is called for those "shouldn't happen" errors in the * allocator. */static voidinternalError(void){	EF_Abort("Internal error in allocator.");}/* * initialize sets up the memory allocation arena and the run-time * configuration information. */static voidinitialize(void){	size_t	size = MEMORY_CREATION_SIZE;	size_t	slack;	char *	string;	Slot *	slot;	EF_Print(version);	/*	 * Import the user's environment specification of the default	 * alignment for malloc(). We want that alignment to be under	 * user control, since smaller alignment lets us catch more bugs,	 * however some software will break if malloc() returns a buffer	 * that is not word-aligned.	 *	 * I would like	 * alignment to be zero so that we could catch all one-byte	 * overruns, however if malloc() is asked to allocate an odd-size	 * buffer and returns an address that is not word-aligned, or whose	 * size is not a multiple of the word size, software breaks.	 * This was the case with the Sun string-handling routines,	 * which can do word fetches up to three bytes beyond the end of a	 * string. I handle this problem in part by providing	 * byte-reference-only versions of the string library functions, but	 * there are other functions that break, too. Some in X Windows, one	 * in Sam Leffler's TIFF library, and doubtless many others.	 */	if ( EF_ALIGNMENT == -1 ) {		if ( (string = getenv("EF_ALIGNMENT")) != 0 )			EF_ALIGNMENT = (size_t)atoi(string);		else			EF_ALIGNMENT = sizeof(int);	}	/*	 * See if the user wants to protect the address space below a buffer,	 * rather than that above a buffer.	 */	if ( EF_PROTECT_BELOW == -1 ) {		if ( (string = getenv("EF_PROTECT_BELOW")) != 0 )			EF_PROTECT_BELOW = (atoi(string) != 0);		else			EF_PROTECT_BELOW = 0;	}	/*	 * See if the user wants to protect memory that has been freed until	 * the program exits, rather than until it is re-allocated.	 */	if ( EF_PROTECT_FREE == -1 ) {		if ( (string = getenv("EF_PROTECT_FREE")) != 0 )			EF_PROTECT_FREE = (atoi(string) != 0);		else			EF_PROTECT_FREE = 0;	}	/*	 * See if the user wants to allow malloc(0).	 */	if ( EF_ALLOW_MALLOC_0 == -1 ) {		if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )			EF_ALLOW_MALLOC_0 = (atoi(string) != 0);		else			EF_ALLOW_MALLOC_0 = 0;	}	/*	 * Get the run-time configuration of the virtual memory page size. 	 */	bytesPerPage = Page_Size();	/*	 * Figure out how many Slot structures to allocate at one time.	 */	slotCount = slotsPerPage = bytesPerPage / sizeof(Slot);	allocationListSize = bytesPerPage;	if ( allocationListSize > size )		size = allocationListSize;	if ( (slack = size % bytesPerPage) != 0 )		size += bytesPerPage - slack;	/*	 * Allocate memory, and break it up into two malloc buffers. The	 * first buffer will be used for Slot structures, the second will	 * be marked free.	 */	slot = allocationList = (Slot *)Page_Create(size);	memset((char *)allocationList, 0, allocationListSize);	slot[0].internalSize = slot[0].userSize = allocationListSize;	slot[0].internalAddress = slot[0].userAddress = allocationList;	slot[0].mode = INTERNAL_USE;	if ( size > allocationListSize ) {		slot[1].internalAddress = slot[1].userAddress		 = ((char *)slot[0].internalAddress) + slot[0].internalSize;		slot[1].internalSize		 = slot[1].userSize = size - slot[0].internalSize;		slot[1].mode = FREE;	}	/*	 * Deny access to the free page, so that we will detect any software	 * that treads upon free memory.	 */	Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);	/*	 * Account for the two slot structures that we've used.	 */	unUsedSlots = slotCount - 2;}/* * allocateMoreSlots is called when there are only enough slot structures * left to support the allocation of a single malloc buffer. */static voidallocateMoreSlots(void){	size_t	newSize = allocationListSize + bytesPerPage;	void *	newAllocation;	void *	oldAllocation = allocationList;	Page_AllowAccess(allocationList, allocationListSize);	noAllocationListProtection = 1;	internalUse = 1;	newAllocation = malloc(newSize);	memcpy(newAllocation, allocationList, allocationListSize);	memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage);	allocationList = (Slot *)newAllocation;	allocationListSize = newSize;	slotCount += slotsPerPage;	unUsedSlots += slotsPerPage;	free(oldAllocation);	/*	 * Keep access to the allocation list open at this point, because	 * I am returning to memalign(), which needs that access. 	 */	noAllocationListProtection = 0;	internalUse = 0;}/* * This is the memory allocator. When asked to allocate a buffer, allocate * it in such a way that the end of the buffer is followed by an inaccessable * memory page. If software overruns that buffer, it will touch the bad page * and get an immediate segmentation fault. It's then easy to zero in on the * offending code with a debugger. * * There are a few complications. If the user asks for an odd-sized buffer, * we would have to have that buffer start on an odd address if the byte after * the end of the buffer was to be on the inaccessable page. Unfortunately, * there is lots of software that asks for odd-sized buffers and then * requires that the returned address be word-aligned, or the size of the * buffer be a multiple of the word size. An example are the string-processing * functions on Sun systems, which do word references to the string memory * and may refer to memory up to three bytes beyond the end of the string. * For this reason, I take the alignment requests to memalign() and valloc() * seriously, and  *  * Electric Fence wastes lots of memory. I do a best-fit allocator here * so that it won't waste even more. It's slow, but thrashing because your * working set is too big for a system's RAM is even slower.  */extern C_LINKAGE void *memalign(size_t alignment, size_t userSize){	register Slot *	slot;	register size_t	count;	Slot *		fullSlot = 0;	Slot *		emptySlots[2];	size_t		internalSize;	size_t		slack;	char *		address;	if ( allocationList == 0 )		initialize();	if ( userSize == 0 && !EF_ALLOW_MALLOC_0 )		EF_Abort("Allocating 0 bytes, probably a bug.");	/*	 * If EF_PROTECT_BELOW is set, all addresses returned by malloc()	 * and company will be page-aligned. 	 */	if ( !EF_PROTECT_BELOW && alignment > 1 ) {		if ( (slack = userSize % alignment) != 0 )			userSize += alignment - slack;	}	/*	 * The internal size of the buffer is rounded up to the next page-size	 * boudary, and then we add another page's worth of memory for the	 * dead page.	 */	internalSize = userSize + bytesPerPage;	if ( (slack = internalSize % bytesPerPage) != 0 )		internalSize += bytesPerPage - slack;	/*	 * These will hold the addresses of two empty Slot structures, that

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -