/src/rocksdb/fuzz/db_map_fuzzer.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) 2011-present, Facebook, Inc. All rights reserved. |
2 | | // This source code is licensed under both the GPLv2 (found in the |
3 | | // COPYING file in the root directory) and Apache 2.0 License |
4 | | // (found in the LICENSE.Apache file in the root directory). |
5 | | |
6 | | #include <algorithm> |
7 | | #include <iostream> |
8 | | #include <map> |
9 | | #include <string> |
10 | | |
11 | | #include "proto/gen/db_operation.pb.h" |
12 | | #include "rocksdb/db.h" |
13 | | #include "rocksdb/file_system.h" |
14 | | #include "src/libfuzzer/libfuzzer_macro.h" |
15 | | #include "util.h" |
16 | | |
17 | | protobuf_mutator::libfuzzer::PostProcessorRegistration<DBOperations> reg = { |
18 | 4.51k | [](DBOperations* input, unsigned int /* seed */) { |
19 | 4.51k | const ROCKSDB_NAMESPACE::Comparator* comparator = |
20 | 4.51k | ROCKSDB_NAMESPACE::BytewiseComparator(); |
21 | 4.51k | auto ops = input->mutable_operations(); |
22 | | // Make sure begin <= end for DELETE_RANGE. |
23 | 1.56M | for (DBOperation& op : *ops) { |
24 | 1.56M | if (op.type() == OpType::DELETE_RANGE) { |
25 | 515k | auto begin = op.key(); |
26 | 515k | auto end = op.value(); |
27 | 515k | if (comparator->Compare(begin, end) > 0) { |
28 | 2.14k | std::swap(begin, end); |
29 | 2.14k | op.set_key(begin); |
30 | 2.14k | op.set_value(end); |
31 | 2.14k | } |
32 | 515k | } |
33 | 1.56M | } |
34 | 4.51k | }}; |
35 | | |
36 | | // Execute randomly generated operations on both a DB and a std::map, |
37 | | // then reopen the DB and make sure that iterating the DB produces the |
38 | | // same key-value pairs as iterating through the std::map. |
39 | 4.51k | DEFINE_PROTO_FUZZER(DBOperations& input) { |
40 | 4.51k | if (input.operations().empty()) { |
41 | 3 | return; |
42 | 3 | } |
43 | | |
44 | 4.51k | const std::string kDbPath = "/tmp/db_map_fuzzer_test"; |
45 | 4.51k | auto fs = ROCKSDB_NAMESPACE::FileSystem::Default(); |
46 | 4.51k | if (fs->FileExists(kDbPath, ROCKSDB_NAMESPACE::IOOptions(), /*dbg=*/nullptr) |
47 | 4.51k | .ok()) { |
48 | 0 | std::cerr << "db path " << kDbPath << " already exists" << std::endl; |
49 | 0 | abort(); |
50 | 0 | } |
51 | | |
52 | 4.51k | std::map<std::string, std::string> kv; |
53 | 4.51k | ROCKSDB_NAMESPACE::DB* db = nullptr; |
54 | 4.51k | ROCKSDB_NAMESPACE::Options options; |
55 | 4.51k | options.create_if_missing = true; |
56 | 4.51k | CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db)); |
57 | | |
58 | 1.56M | for (const DBOperation& op : input.operations()) { |
59 | 1.56M | switch (op.type()) { |
60 | 660k | case OpType::PUT: { |
61 | 660k | CHECK_OK( |
62 | 660k | db->Put(ROCKSDB_NAMESPACE::WriteOptions(), op.key(), op.value())); |
63 | 660k | kv[op.key()] = op.value(); |
64 | 660k | break; |
65 | 660k | } |
66 | 200k | case OpType::MERGE: { |
67 | 200k | break; |
68 | 660k | } |
69 | 186k | case OpType::DELETE: { |
70 | 186k | CHECK_OK(db->Delete(ROCKSDB_NAMESPACE::WriteOptions(), op.key())); |
71 | 186k | kv.erase(op.key()); |
72 | 186k | break; |
73 | 186k | } |
74 | 515k | case OpType::DELETE_RANGE: { |
75 | | // [op.key(), op.value()) corresponds to [begin, end). |
76 | 515k | CHECK_OK(db->DeleteRange(ROCKSDB_NAMESPACE::WriteOptions(), |
77 | 515k | db->DefaultColumnFamily(), op.key(), |
78 | 515k | op.value())); |
79 | 515k | kv.erase(kv.lower_bound(op.key()), kv.lower_bound(op.value())); |
80 | 515k | break; |
81 | 515k | } |
82 | 0 | default: { |
83 | 0 | std::cerr << "Unsupported operation" << static_cast<int>(op.type()); |
84 | 0 | return; |
85 | 515k | } |
86 | 1.56M | } |
87 | 1.56M | } |
88 | 4.51k | CHECK_OK(db->Close()); |
89 | 4.51k | delete db; |
90 | 4.51k | db = nullptr; |
91 | | |
92 | 4.51k | CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db)); |
93 | 4.51k | auto kv_it = kv.begin(); |
94 | 4.51k | ROCKSDB_NAMESPACE::Iterator* it = |
95 | 4.51k | db->NewIterator(ROCKSDB_NAMESPACE::ReadOptions()); |
96 | 34.1k | for (it->SeekToFirst(); it->Valid(); it->Next(), kv_it++) { |
97 | 29.5k | CHECK_TRUE(kv_it != kv.end()); |
98 | 29.5k | CHECK_EQ(it->key().ToString(), kv_it->first); |
99 | 29.5k | CHECK_EQ(it->value().ToString(), kv_it->second); |
100 | 29.5k | } |
101 | 4.51k | CHECK_TRUE(kv_it == kv.end()); |
102 | 4.51k | delete it; |
103 | | |
104 | 4.51k | CHECK_OK(db->Close()); |
105 | 4.51k | delete db; |
106 | 4.51k | CHECK_OK(ROCKSDB_NAMESPACE::DestroyDB(kDbPath, options)); |
107 | 4.51k | } |