Coverage Report

Created: 2025-11-09 06:47

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