view fuzz-wrapfd.c @ 1356:3677a510f545 fuzz

add wrapfd. improve fuzzer in makefile
author Matt Johnston <matt@ucc.asn.au>
date Fri, 19 May 2017 00:48:46 +0800
parents
children 08f4fa4dc6a0
line wrap: on
line source

#include "includes.h"
#include "fuzz-wrapfd.h"

static const int IOWRAP_MAXFD = FD_SETSIZE-1;
static const int MAX_RANDOM_IN = 50000;
static const double CHANCE_CLOSE = 1.0 / 300;
static const double CHANCE_INTR = 1.0 / 200;
static const double CHANCE_READ1 = 0.6;
static const double CHANCE_READ2 = 0.3;
static const double CHANCE_WRITE1 = 0.8;
static const double CHANCE_WRITE2 = 0.3;

struct fdwrap {
	enum wrapfd_mode mode;
	buffer *buf;
};

static struct fdwrap wrap_fds[IOWRAP_MAXFD+1];
// for quick selection of in-use descriptors
static int wrap_used[IOWRAP_MAXFD+1];
static unsigned int nused;
static unsigned short rand_state[3];

void wrapfd_setup(uint32_t seed) {
	nused = 0;
	memset(wrap_fds, 0x0, sizeof(wrap_fds));

	*((uint32_t*)rand_state) = seed;
	nrand48(rand_state);
}

void wrapfd_add(int fd, buffer *buf, enum wrapfd_mode mode) {
	assert(fd >= 0);
	assert(fd <= IOWRAP_MAXFD);
	assert(wrap_fds[fd].mode == UNUSED);
	assert(buf || mode == RANDOMIN);

	wrap_fds[fd].mode = mode;
	wrap_fds[fd].buf = buf;
	wrap_used[nused] = fd;

	nused++;
}

void wrapfd_remove(int fd) {
	unsigned int i, j;
	assert(fd >= 0);
	assert(fd <= IOWRAP_MAXFD);
	assert(wrap_fds[fd].mode != UNUSED);
	wrap_fds[fd].mode = UNUSED;

	// remove from used list
	for (i = 0, j = 0; i < nused; i++) {
		if (wrap_used[i] != fd) {
			wrap_used[j] = wrap_used[i];
			j++;
		}
	}
	nused--;
}


int wrapfd_read(int fd, void *out, size_t count) {
	size_t maxread;
	buffer *buf;

	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode != UNUSED) {
		TRACE(("Bad read descriptor %d\n", fd))
		errno = EBADF;
		return -1;
	}

	assert(count != 0);

	if (erand48(rand_state) < CHANCE_CLOSE) {
		wrapfd_remove(fd);
		return 0;
	}

	if (erand48(rand_state) < CHANCE_INTR) {
		errno = EINTR;
		return -1;
	}

	buf = wrap_fds[fd].buf;
	if (buf) {
		maxread = MIN(buf->len - buf->pos, count);
		// returns 0 if buf is EOF, as intended
		maxread = nrand48(rand_state) % maxread + 1;
		memcpy(out, buf_getptr(buf, maxread), maxread);
		buf_incrpos(buf, maxread);
		return maxread;
	}

	maxread = MIN(MAX_RANDOM_IN, count);
	maxread = nrand48(rand_state) % maxread + 1;
	memset(out, 0xef, maxread);
	return maxread;
}

int wrapfd_write(int fd, const void* in, size_t count) {
	unsigned const volatile char* volin = in;
	unsigned int i;
	if (fd < 0 || fd > IOWRAP_MAXFD || wrap_fds[fd].mode != UNUSED) {
		TRACE(("Bad read descriptor %d\n", fd))
		errno = EBADF;
		return -1;
	}

	assert(count != 0);

	// force read to exercise sanitisers
	for (i = 0; i < count; i++) {
		(void)volin[i];
	}

	if (erand48(rand_state) < CHANCE_CLOSE) {
		wrapfd_remove(fd);
		return 0;
	}

	if (erand48(rand_state) < CHANCE_INTR) {
		errno = EINTR;
		return -1;
	}

	return nrand48(rand_state) % (count+1);
}

int wrapfd_select(int nfds, fd_set *readfds, fd_set *writefds, 
	fd_set *UNUSED(exceptfds), struct timeval *UNUSED(timeout)) {
	int i, nset;
	int ret = 0;
	int fdlist[IOWRAP_MAXFD+1] = {0};

	assert(nfds <= IOWRAP_MAXFD+1);

	if (erand48(rand_state) < CHANCE_INTR) {
		errno = EINTR;
		return -1;
	}

	// read
	if (erand48(rand_state) < CHANCE_READ1) {
		for (i = 0, nset = 0; i < nfds; i++) {
			if (FD_ISSET(i, readfds)) {
				assert(wrap_fds[i].mode != UNUSED);
				fdlist[nset] = i;
			}
		}
		FD_ZERO(readfds);

		if (nset > 0) {
			// set one
			FD_SET(fdlist[random() % nset], readfds);
			ret++;

			if (erand48(rand_state) < CHANCE_READ2) {
				i = fdlist[random() % nset];
				if (!FD_ISSET(i, readfds)) {
					FD_SET(i, readfds);
					ret++;
				}
			}
		}
	}

	// write
	if (erand48(rand_state) < CHANCE_WRITE1) {
		for (i = 0, nset = 0; i < nfds; i++) {
			if (FD_ISSET(i, writefds)) {
				assert(wrap_fds[i].mode != UNUSED);
				fdlist[nset] = i;
			}
		}
		FD_ZERO(writefds);

		// set one
		if (nset > 0) {
			FD_SET(fdlist[nrand48(rand_state) % nset], writefds);
			ret++;

			if (erand48(rand_state) < CHANCE_WRITE2) {
				i = fdlist[nrand48(rand_state) % nset];
				if (!FD_ISSET(i, writefds)) {
					FD_SET(i, writefds);
					ret++;
				}
			}
		}
	}
	return ret;
}