Coverage Report

Created: 2025-08-03 07:12

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