Coverage Report

Created: 2025-11-24 06:55

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