Coverage Report

Created: 2026-10-16 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/leveldb/fuzz_db.cc
Line
Count
Source
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
45
  ~AutoDbDeleter() {
43
45
    std::filesystem::remove_all(kDbPath);
44
45
  }
45
};
46
47
// static
48
constexpr char AutoDbDeleter::kDbPath[];
49
50
// Returns nullptr (a falsey unique_ptr) if opening fails.
51
97
std::unique_ptr<leveldb::DB> OpenDB() {
52
97
  leveldb::Options options;
53
97
  options.create_if_missing = true;
54
55
97
  leveldb::DB* db_ptr;
56
97
  leveldb::Status status =
57
97
      leveldb::DB::Open(options, AutoDbDeleter::kDbPath, &db_ptr);
58
97
  if (!status.ok())
59
0
    return nullptr;
60
61
97
  return std::unique_ptr<leveldb::DB>(db_ptr);
62
97
}
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
45
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
45
  AutoDbDeleter db_deleter;
84
85
45
  std::unique_ptr<leveldb::DB> db = OpenDB();
86
45
  if (!db.get())
87
0
    return 0;
88
89
  // Perform a sequence of operations on the database.
90
45
  FuzzedDataProvider fuzzed_data(data, size);
91
582
  while (fuzzed_data.remaining_bytes() != 0) {
92
537
    FuzzOp fuzz_op = fuzzed_data.ConsumeEnum<FuzzOp>();
93
94
537
    switch (fuzz_op) {
95
418
    case FuzzOp::kPut: {
96
418
      std::string key = fuzzed_data.ConsumeRandomLengthString();
97
418
      std::string value = fuzzed_data.ConsumeRandomLengthString();
98
418
      db->Put(leveldb::WriteOptions(), key, value);
99
418
      break;
100
0
    }
101
21
    case FuzzOp::kGet: {
102
21
      std::string key = fuzzed_data.ConsumeRandomLengthString();
103
21
      std::string value;
104
21
      db->Get(leveldb::ReadOptions(), key, &value);
105
21
      break;
106
0
    }
107
15
    case FuzzOp::kDelete: {
108
15
      std::string key = fuzzed_data.ConsumeRandomLengthString();
109
15
      db->Delete(leveldb::WriteOptions(), key);
110
15
      break;
111
0
    }
112
13
    case FuzzOp::kGetProperty: {
113
13
      std::string name = fuzzed_data.ConsumeRandomLengthString();
114
13
      std::string value;
115
13
      db->GetProperty(name, &value);
116
13
      break;
117
0
    }
118
10
    case FuzzOp::kIterate: {
119
10
      std::unique_ptr<leveldb::Iterator> it(
120
10
          db->NewIterator(leveldb::ReadOptions()));
121
184
      for (it->SeekToFirst(); it->Valid(); it->Next())
122
174
        continue;
123
10
    }
124
24
    case FuzzOp::kGetReleaseSnapshot: {
125
24
      leveldb::ReadOptions snapshot_options;
126
24
      snapshot_options.snapshot = db->GetSnapshot();
127
24
      std::unique_ptr<leveldb::Iterator> it(db->NewIterator(snapshot_options));
128
24
      db->ReleaseSnapshot(snapshot_options.snapshot);
129
24
    }
130
52
    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
52
      db.reset();
134
52
      db = OpenDB();
135
52
      if (!db)
136
0
        return 0;  // Reopening the database failed.
137
52
      break;
138
52
    }
139
52
    case FuzzOp::kCompactRange: {
140
18
      std::string begin_key = fuzzed_data.ConsumeRandomLengthString();
141
18
      std::string end_key =  fuzzed_data.ConsumeRandomLengthString();
142
18
      leveldb::Slice begin_slice(begin_key);
143
18
      leveldb::Slice end_slice(end_key);
144
18
      db->CompactRange(&begin_slice, &end_slice);
145
18
      break;
146
52
    }
147
537
    }
148
537
  }
149
150
45
  return 0;
151
45
}