// 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;
}