aboutsummaryrefslogtreecommitdiff
path: root/projects/leveldb/fuzz_db.cc
diff options
context:
space:
mode:
Diffstat (limited to 'projects/leveldb/fuzz_db.cc')
-rw-r--r--projects/leveldb/fuzz_db.cc151
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;
+}