If I want to check for overflow, then I should check it before I do base + incr, not after. Now that I have no check, I am passing the overflowed base + incr to brk1(), where it will probably fail the nbreak < segment check.
		
			
				
	
	
		
			86 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			86 lines
		
	
	
	
		
			1.9 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * This emulates brk() and sbrk() using mmap() and mprotect().
 | 
						|
 *
 | 
						|
 * We reserve exactly SEGMENTSZ bytes of address space by calling
 | 
						|
 * mmap() with PROT_NONE.  Then we allocate pages in our segment by
 | 
						|
 * calling mprotect() with PROT_READ|PROT_WRITE.
 | 
						|
 *
 | 
						|
 * This emulation can't resize its segment.  If SEGMENTSZ is too big,
 | 
						|
 * then programs might run out of address space for other mappings.
 | 
						|
 */
 | 
						|
#include <sys/mman.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <unistd.h>
 | 
						|
 | 
						|
/*
 | 
						|
 * PAGESZ must be correct for this system!
 | 
						|
 * SEGMENTSZ must be a multiple of PAGESZ.
 | 
						|
 */
 | 
						|
#define PAGESZ 0x1000		/* page size for i386, powerpc */
 | 
						|
#define SEGMENTSZ 0x20000000
 | 
						|
 | 
						|
static char *segment;
 | 
						|
static char *cbreak;		/* current break */
 | 
						|
 | 
						|
static void brk_init(void)
 | 
						|
{
 | 
						|
	/*
 | 
						|
	 * Try exactly once to reserve our segment.  If we fail, then
 | 
						|
	 * segment == MAP_FAILED and we never try again.
 | 
						|
	 */
 | 
						|
	if (segment == NULL) {
 | 
						|
		segment = mmap(NULL, SEGMENTSZ, PROT_NONE,
 | 
						|
		    MAP_PRIVATE|MAP_ANON, -1, 0);
 | 
						|
		cbreak = segment;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static int brk1(char *nbreak)
 | 
						|
{
 | 
						|
	size_t sz;
 | 
						|
	char *new, *old;
 | 
						|
 | 
						|
	sz = (segment == MAP_FAILED) ? 0 : SEGMENTSZ;
 | 
						|
	if (nbreak < segment || nbreak > segment + sz) {
 | 
						|
		errno = ENOMEM;
 | 
						|
		return -1;
 | 
						|
	}
 | 
						|
 | 
						|
	/* Round up to page size. */
 | 
						|
	old = (char *)(((size_t)cbreak + (PAGESZ-1)) & ~(PAGESZ-1));
 | 
						|
	new = (char *)(((size_t)nbreak + (PAGESZ-1)) & ~(PAGESZ-1));
 | 
						|
 | 
						|
	if (new > old) {
 | 
						|
		/* Allocate pages by unprotecting them. */
 | 
						|
		if (mprotect(old, new - old, PROT_READ|PROT_WRITE) < 0) {
 | 
						|
			errno = ENOMEM;
 | 
						|
			return -1;
 | 
						|
		}
 | 
						|
	} else if (new < old) {
 | 
						|
		/*
 | 
						|
		 * Free pages by using MAP_FIXED to replace the
 | 
						|
		 * mapping.  Ignore errors.
 | 
						|
		 */
 | 
						|
		mmap(new, old - new, PROT_NONE,
 | 
						|
		    MAP_PRIVATE|MAP_ANON|MAP_FIXED, -1, 0);
 | 
						|
	}
 | 
						|
	cbreak = nbreak;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
int brk(void *addr)
 | 
						|
{
 | 
						|
	brk_init();
 | 
						|
	return brk1(addr);
 | 
						|
}
 | 
						|
 | 
						|
void *sbrk(int incr)
 | 
						|
{
 | 
						|
	char *base;
 | 
						|
 | 
						|
	brk_init();
 | 
						|
	base = cbreak;
 | 
						|
	if (brk1(base + incr) < 0)
 | 
						|
		return (void*)-1;
 | 
						|
	return base;
 | 
						|
}
 |