Coverage Report

Created: 2026-05-24 06:32

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
48
  ~AutoDbDeleter() {
43
48
    std::filesystem::remove_all(kDbPath);
44
48
  }
45
};
46
47
// static
48
constexpr char AutoDbDeleter::kDbPath[];
49
50
// Returns nullptr (a falsey unique_ptr) if opening fails.
51
100
std::unique_ptr<leveldb::DB> OpenDB() {
52
100
  leveldb::Options options;
53
100
  options.create_if_missing = true;
54
55
100
  leveldb::DB* db_ptr;
56
100
  leveldb::Status status =
57
100
      leveldb::DB::Open(options, AutoDbDeleter::kDbPath, &db_ptr);
58
100
  if (!status.ok())
59
0
    return nullptr;
60
61
100
  return std::unique_ptr<leveldb::DB>(db_ptr);
62
100
}
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
48
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
48
  AutoDbDeleter db_deleter;
84
85
48
  std::unique_ptr<leveldb::DB> db = OpenDB();
86
48
  if (!db.get())
87
0
    return 0;
88
89
  // Perform a sequence of operations on the database.
90
48
  FuzzedDataProvider fuzzed_data(data, size);
91
588
  while (fuzzed_data.remaining_bytes() != 0) {
92
540
    FuzzOp fuzz_op = fuzzed_data.ConsumeEnum<FuzzOp>();
93
94
540
    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
22
    case FuzzOp::kGet: {
102
22
      std::string key = fuzzed_data.ConsumeRandomLengthString();
103
22
      std::string value;
104
22
      db->Get(leveldb::ReadOptions(), key, &value);
105
22
      break;
106
0
    }
107
16
    case FuzzOp::kDelete: {
108
16
      std::string key = fuzzed_data.ConsumeRandomLengthString();
109
16
      db->Delete(leveldb::WriteOptions(), key);
110
16
      break;
111
0
    }
112
14
    case FuzzOp::kGetProperty: {
113
14
      std::string name = fuzzed_data.ConsumeRandomLengthString();
114
14
      std::string value;
115
14
      db->GetProperty(name, &value);
116
14
      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
540
    }
148
540
  }
149
150
48
  return 0;
151
48
}