Coverage Report

Created: 2025-08-28 07:01

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