Coverage Report

Created: 2022-11-21 06:53

/src/leveldb/fuzz_db.cc
Line
Count
Source (jump to first uncovered line)
1
/* Copyright 2020 Google Inc.
2
3
Licensed under the Apache License, Version 2.0 (the "License");
4
you may not use this file except in compliance with the License.
5
You may obtain a copy of the License at
6
7
      http://www.apache.org/licenses/LICENSE-2.0
8
9
Unless required by applicable law or agreed to in writing, software
10
distributed under the License is distributed on an "AS IS" BASIS,
11
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
See the License for the specific language governing permissions and
13
limitations under the License.
14
*/
15
16
17
#include <cstdint>
18
#include <cstddef>
19
#include <filesystem>
20
#include <memory>
21
#include <string>
22
23
#include "leveldb/db.h"
24
#include "leveldb/iterator.h"
25
#include "leveldb/options.h"
26
#include "leveldb/status.h"
27
28
#include <fuzzer/FuzzedDataProvider.h>
29
30
namespace {
31
32
// Deletes the database directory when going out of scope.
33
class AutoDbDeleter {
34
 public:
35
  static constexpr char kDbPath[] = "/tmp/testdb";
36
37
  AutoDbDeleter() = default;
38
39
  AutoDbDeleter(const AutoDbDeleter&) = delete;
40
  AutoDbDeleter& operator=(const AutoDbDeleter&) = delete;
41
42
5.54k
  ~AutoDbDeleter() {
43
5.54k
    std::__fs::filesystem::remove_all(kDbPath);
44
5.54k
  }
45
};
46
47
// static
48
constexpr char AutoDbDeleter::kDbPath[];
49
50
// Returns nullptr (a falsey unique_ptr) if opening fails.
51
121k
std::unique_ptr<leveldb::DB> OpenDB() {
52
121k
  leveldb::Options options;
53
121k
  options.create_if_missing = true;
54
55
121k
  leveldb::DB* db_ptr;
56
121k
  leveldb::Status status =
57
121k
      leveldb::DB::Open(options, AutoDbDeleter::kDbPath, &db_ptr);
58
121k
  if (!status.ok())
59
0
    return nullptr;
60
61
121k
  return std::unique_ptr<leveldb::DB>(db_ptr);
62
121k
}
63
64
enum class FuzzOp {
65
  kPut = 0,
66
  kGet = 1,
67
  kDelete = 2,
68
  kGetProperty = 3,
69
  kIterate = 4,
70
  kGetReleaseSnapshot = 5,
71
  kReopenDb = 6,
72
  kCompactRange = 7,
73
  // Add new values here.
74
75
  // When adding new values, update to the last value above.
76
  kMaxValue = kCompactRange,
77
};
78
79
}  // namespace
80
81
5.54k
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
82
  // Must occur before `db` so the deletion doesn't happen while the DB is open.
83
5.54k
  AutoDbDeleter db_deleter;
84
85
5.54k
  std::unique_ptr<leveldb::DB> db = OpenDB();
86
5.54k
  if (!db.get())
87
0
    return 0;
88
89
  // Perform a sequence of operations on the database.
90
5.54k
  FuzzedDataProvider fuzzed_data(data, size);
91
2.59M
  while (fuzzed_data.remaining_bytes() != 0) {
92
2.58M
    FuzzOp fuzz_op = fuzzed_data.ConsumeEnum<FuzzOp>();
93
94
2.58M
    switch (fuzz_op) {
95
53.9k
    case FuzzOp::kPut: {
96
53.9k
      std::string key = fuzzed_data.ConsumeRandomLengthString();
97
53.9k
      std::string value = fuzzed_data.ConsumeRandomLengthString();
98
53.9k
      db->Put(leveldb::WriteOptions(), key, value);
99
53.9k
      break;
100
0
    }
101
43.9k
    case FuzzOp::kGet: {
102
43.9k
      std::string key = fuzzed_data.ConsumeRandomLengthString();
103
43.9k
      std::string value;
104
43.9k
      db->Get(leveldb::ReadOptions(), key, &value);
105
43.9k
      break;
106
0
    }
107
2.34M
    case FuzzOp::kDelete: {
108
2.34M
      std::string key = fuzzed_data.ConsumeRandomLengthString();
109
2.34M
      db->Delete(leveldb::WriteOptions(), key);
110
2.34M
      break;
111
0
    }
112
8.40k
    case FuzzOp::kGetProperty: {
113
8.40k
      std::string name = fuzzed_data.ConsumeRandomLengthString();
114
8.40k
      std::string value;
115
8.40k
      db->GetProperty(name, &value);
116
8.40k
      break;
117
0
    }
118
63.2k
    case FuzzOp::kIterate: {
119
63.2k
      std::unique_ptr<leveldb::Iterator> it(
120
63.2k
          db->NewIterator(leveldb::ReadOptions()));
121
428k
      for (it->SeekToFirst(); it->Valid(); it->Next())
122
365k
        continue;
123
63.2k
    }
124
82.6k
    case FuzzOp::kGetReleaseSnapshot: {
125
82.6k
      leveldb::ReadOptions snapshot_options;
126
82.6k
      snapshot_options.snapshot = db->GetSnapshot();
127
82.6k
      std::unique_ptr<leveldb::Iterator> it(db->NewIterator(snapshot_options));
128
82.6k
      db->ReleaseSnapshot(snapshot_options.snapshot);
129
82.6k
    }
130
115k
    case FuzzOp::kReopenDb: {
131
      // The database must be closed before attempting to reopen it. Otherwise,
132
      // the open will fail due to exclusive locking.
133
115k
      db.reset();
134
115k
      db = OpenDB();
135
115k
      if (!db)
136
0
        return 0;  // Reopening the database failed.
137
115k
      break;
138
115k
    }
139
115k
    case FuzzOp::kCompactRange: {
140
26.5k
      std::string begin_key = fuzzed_data.ConsumeRandomLengthString();
141
26.5k
      std::string end_key =  fuzzed_data.ConsumeRandomLengthString();
142
26.5k
      leveldb::Slice begin_slice(begin_key);
143
26.5k
      leveldb::Slice end_slice(end_key);
144
26.5k
      db->CompactRange(&begin_slice, &end_slice);
145
26.5k
      break;
146
115k
    }
147
2.58M
    }
148
2.58M
  }
149
150
5.54k
  return 0;
151
5.54k
}