diff options
Diffstat (limited to 'projects/leveldb/fuzz_db.cc')
-rw-r--r-- | projects/leveldb/fuzz_db.cc | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/projects/leveldb/fuzz_db.cc b/projects/leveldb/fuzz_db.cc new file mode 100644 index 000000000..0147c124f --- /dev/null +++ b/projects/leveldb/fuzz_db.cc @@ -0,0 +1,151 @@ +/* Copyright 2020 Google Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + + +#include <cstdint> +#include <cstddef> +#include <filesystem> +#include <memory> +#include <string> + +#include "leveldb/db.h" +#include "leveldb/iterator.h" +#include "leveldb/options.h" +#include "leveldb/status.h" + +#include <fuzzer/FuzzedDataProvider.h> + +namespace { + +// Deletes the database directory when going out of scope. +class AutoDbDeleter { + public: + static constexpr char kDbPath[] = "/tmp/testdb"; + + AutoDbDeleter() = default; + + AutoDbDeleter(const AutoDbDeleter&) = delete; + AutoDbDeleter& operator=(const AutoDbDeleter&) = delete; + + ~AutoDbDeleter() { + std::__fs::filesystem::remove_all(kDbPath); + } +}; + +// static +constexpr char AutoDbDeleter::kDbPath[]; + +// Returns nullptr (a falsey unique_ptr) if opening fails. +std::unique_ptr<leveldb::DB> OpenDB() { + leveldb::Options options; + options.create_if_missing = true; + + leveldb::DB* db_ptr; + leveldb::Status status = + leveldb::DB::Open(options, AutoDbDeleter::kDbPath, &db_ptr); + if (!status.ok()) + return nullptr; + + return std::unique_ptr<leveldb::DB>(db_ptr); +} + +enum class FuzzOp { + kPut = 0, + kGet = 1, + kDelete = 2, + kGetProperty = 3, + kIterate = 4, + kGetReleaseSnapshot = 5, + kReopenDb = 6, + kCompactRange = 7, + // Add new values here. + + // When adding new values, update to the last value above. + kMaxValue = kCompactRange, +}; + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { + // Must occur before `db` so the deletion doesn't happen while the DB is open. + AutoDbDeleter db_deleter; + + std::unique_ptr<leveldb::DB> db = OpenDB(); + if (!db.get()) + return 0; + + // Perform a sequence of operations on the database. + FuzzedDataProvider fuzzed_data(data, size); + while (fuzzed_data.remaining_bytes() != 0) { + FuzzOp fuzz_op = fuzzed_data.ConsumeEnum<FuzzOp>(); + + switch (fuzz_op) { + case FuzzOp::kPut: { + std::string key = fuzzed_data.ConsumeRandomLengthString(); + std::string value = fuzzed_data.ConsumeRandomLengthString(); + db->Put(leveldb::WriteOptions(), key, value); + break; + } + case FuzzOp::kGet: { + std::string key = fuzzed_data.ConsumeRandomLengthString(); + std::string value; + db->Get(leveldb::ReadOptions(), key, &value); + break; + } + case FuzzOp::kDelete: { + std::string key = fuzzed_data.ConsumeRandomLengthString(); + db->Delete(leveldb::WriteOptions(), key); + break; + } + case FuzzOp::kGetProperty: { + std::string name = fuzzed_data.ConsumeRandomLengthString(); + std::string value; + db->GetProperty(name, &value); + break; + } + case FuzzOp::kIterate: { + std::unique_ptr<leveldb::Iterator> it( + db->NewIterator(leveldb::ReadOptions())); + for (it->SeekToFirst(); it->Valid(); it->Next()) + continue; + } + case FuzzOp::kGetReleaseSnapshot: { + leveldb::ReadOptions snapshot_options; + snapshot_options.snapshot = db->GetSnapshot(); + std::unique_ptr<leveldb::Iterator> it(db->NewIterator(snapshot_options)); + db->ReleaseSnapshot(snapshot_options.snapshot); + } + case FuzzOp::kReopenDb: { + // The database must be closed before attempting to reopen it. Otherwise, + // the open will fail due to exclusive locking. + db.reset(); + db = OpenDB(); + if (!db) + return 0; // Reopening the database failed. + break; + } + case FuzzOp::kCompactRange: { + std::string begin_key = fuzzed_data.ConsumeRandomLengthString(); + std::string end_key = fuzzed_data.ConsumeRandomLengthString(); + leveldb::Slice begin_slice(begin_key); + leveldb::Slice end_slice(end_key); + db->CompactRange(&begin_slice, &end_slice); + break; + } + } + } + + return 0; +} |