Coverage Report

Created: 2026-09-14 06:40

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