aboutsummaryrefslogblamecommitdiff
path: root/fuzz/simple_ops.c
blob: a7f501ee30071b01353a1ef0bd7eedc66f04b110 (plain) (tree)

































































































































































                                                                                               
// SPDX-License-Identifier: LGPL-3.0-or-later

#include <hkvs.h>
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

inline static int rdlen(size_t *pr, const uint8_t **pd, size_t *pn) {
	const uint8_t *d = *pd;
	size_t n = *pn;
	if(n == 0) return -1;
	*pd = d + 1;
	*pn = n - 1;
	*pr = d[0];
	return 0;
}

static const char zeroes[256];

static void no_io_destroy(hkvs_io *io) {
	(void)io;
}

inline static void check_error(int r) {
	if(r < 0) {
		fprintf(stderr, "Error: %s\n", strerror(-r));
		abort();
	}
}

extern int LLVMFuzzerTestOneInput(const uint8_t *fz_data, size_t fz_n);
int LLVMFuzzerTestOneInput(const uint8_t *fz_data, size_t fz_n) {
	bool log = false;

	if(fz_n < 8) return 0;
	hkvs_io *io;
	{
		uint64_t seed;
		memcpy(&seed, fz_data, 8);
		fz_data += 8;
		fz_n -= 8;
		io = hkvs_io_new_mem(seed);
	}

	size_t sizes[256];
	for(size_t i = 0; i < 256; i++) {
		sizes[i] = (size_t)-1;
	}

	hkvs *db;
	int r = hkvs_new(&db, io);
	if(r == -E2BIG) return 0;
	check_error(r);

	hkvs_table *t;
	r = hkvs_table_create(db, &t, 42, 1, 16);
	check_error(r);
	assert(r == 1);

	hkvs_rid id = HKVS_INVALID_RID;
	uint8_t id_k = 0;

	if(log) puts("begin");

	while(fz_n) {
		uint8_t op = *fz_data++;
		fz_n--;

		switch(op) {
			case 0:
			{
				if(log) puts("reopen");

				void (*old_destroy)(hkvs_io*) = io->destroy;
				io->destroy = no_io_destroy;
				hkvs_free(db);
				io->destroy = old_destroy;

				r = hkvs_new(&db, io);
				check_error(r);

				r = hkvs_table_create(db, &t, 42, 1, 16);
				check_error(r);
				assert(r == 0);
				id = HKVS_INVALID_RID;
				break;
			}
			case 3:
			{
				if(fz_n < 1) goto end;
				uint8_t k = *fz_data;
				fz_data++;
				fz_n--;
				if(log) printf("find %02x ", k);
				id = hkvs_record_find(db, t, (const char *)&k);
				if(hkvs_rid_ok(id)) {
					id_k = k;
					assert(!memcmp(hkvs_record_key(db, t, id), &k, 1));
					size_t len;
					char *val;
					r = hkvs_record_value(db, t, id, &val, &len);
					check_error(r);
					if(log) printf("[%zu]\n", len);
					assert(len == sizes[k]);
				} else {
					if(log) puts("not found");
					assert(sizes[k] == (size_t)-1);
				}
				break;
			}
			case 4:
			{
				if(!hkvs_rid_ok(id)) break;
				if(log) printf("delete %02x\n", id_k);
				hkvs_record_delete(db, t, id);
				sizes[id_k] = (size_t)-1;
				id = HKVS_INVALID_RID;
				break;
			}
			case 5:
			{
				if(!hkvs_rid_ok(id)) break;
				size_t n;
				r = rdlen(&n, &fz_data, &fz_n);
				if(r < 0) goto end;
				if(log) printf("set %02x [%zu]\n", id_k, n);
				r = hkvs_record_set(db, t, id, zeroes, n);
				check_error(r);
				sizes[id_k] = n;
				break;
			}
			case 6:
			{
				if(fz_n < 1) goto end;
				uint8_t k = *fz_data;
				fz_data++;
				fz_n--;
				size_t n;
				r = rdlen(&n, &fz_data, &fz_n);
				if(r < 0) goto end;
				if(log) printf("update %02x [%zu]\n", k, n);
				r = hkvs_record_update(db, t, &id, (const char*)&k, zeroes, n);
				check_error(r);
				if(r) {
					assert(sizes[k] == (size_t)-1);
				} else {
					assert(sizes[k] != (size_t)-1);
				}
				id_k = k;
				sizes[k] = n;
				break;
			}
		}
	}

end:
	hkvs_free(db);

	return 0;
}