Coverage Report

Created: 2025-12-31 06:35

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
114k
std::unique_ptr<leveldb::DB> OpenDB() {
52
114k
  leveldb::Options options;
53
114k
  options.create_if_missing = true;
54
55
114k
  leveldb::DB* db_ptr;
56
114k
  leveldb::Status status =
57
114k
      leveldb::DB::Open(options, AutoDbDeleter::kDbPath, &db_ptr);
58
114k
  if (!status.ok())
59
0
    return nullptr;
60
61
114k
  return std::unique_ptr<leveldb::DB>(db_ptr);
62
114k
}
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.13M
  while (fuzzed_data.remaining_bytes() != 0) {
92
2.12M
    FuzzOp fuzz_op = fuzzed_data.ConsumeEnum<FuzzOp>();
93
94
2.12M
    switch (fuzz_op) {
95
50.5k
    case FuzzOp::kPut: {
96
50.5k
      std::string key = fuzzed_data.ConsumeRandomLengthString();
97
50.5k
      std::string value = fuzzed_data.ConsumeRandomLengthString();
98
50.5k
      db->Put(leveldb::WriteOptions(), key, value);
99
50.5k
      break;
100
0
    }
101
53.1k
    case FuzzOp::kGet: {
102
53.1k
      std::string key = fuzzed_data.ConsumeRandomLengthString();
103
53.1k
      std::string value;
104
53.1k
      db->Get(leveldb::ReadOptions(), key, &value);
105
53.1k
      break;
106
0
    }
107
1.86M
    case FuzzOp::kDelete: {
108
1.86M
      std::string key = fuzzed_data.ConsumeRandomLengthString();
109
1.86M
      db->Delete(leveldb::WriteOptions(), key);
110
1.86M
      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
63.0k
    case FuzzOp::kIterate: {
119
63.0k
      std::unique_ptr<leveldb::Iterator> it(
120
63.0k
          db->NewIterator(leveldb::ReadOptions()));
121
462k
      for (it->SeekToFirst(); it->Valid(); it->Next())
122
399k
        continue;
123
63.0k
    }
124
81.7k
    case FuzzOp::kGetReleaseSnapshot: {
125
81.7k
      leveldb::ReadOptions snapshot_options;
126
81.7k
      snapshot_options.snapshot = db->GetSnapshot();
127
81.7k
      std::unique_ptr<leveldb::Iterator> it(db->NewIterator(snapshot_options));
128
81.7k
      db->ReleaseSnapshot(snapshot_options.snapshot);
129
81.7k
    }
130
109k
    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
109k
      db.reset();
134
109k
      db = OpenDB();
135
109k
      if (!db)
136
0
        return 0;  // Reopening the database failed.
137
109k
      break;
138
109k
    }
139
109k
    case FuzzOp::kCompactRange: {
140
33.5k
      std::string begin_key = fuzzed_data.ConsumeRandomLengthString();
141
33.5k
      std::string end_key =  fuzzed_data.ConsumeRandomLengthString();
142
33.5k
      leveldb::Slice begin_slice(begin_key);
143
33.5k
      leveldb::Slice end_slice(end_key);
144
33.5k
      db->CompactRange(&begin_slice, &end_slice);
145
33.5k
      break;
146
109k
    }
147
2.12M
    }
148
2.12M
  }
149
150
5.01k
  return 0;
151
5.01k
}