// SPDX-License-Identifier: LGPL-3.0-or-later #include #include #include #include #include #include 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; }