Coverage Report

Created: 2026-02-26 06:52

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