Coverage Report

Created: 2025-08-29 06:56

/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.44k
  ~AutoDbDeleter() {
43
5.44k
    std::filesystem::remove_all(kDbPath);
44
5.44k
  }
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.44k
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.44k
  AutoDbDeleter db_deleter;
84
85
5.44k
  std::unique_ptr<leveldb::DB> db = OpenDB();
86
5.44k
  if (!db.get())
87
0
    return 0;
88
89
  // Perform a sequence of operations on the database.
90
5.44k
  FuzzedDataProvider fuzzed_data(data, size);
91
2.43M
  while (fuzzed_data.remaining_bytes() != 0) {
92
2.43M
    FuzzOp fuzz_op = fuzzed_data.ConsumeEnum<FuzzOp>();
93
94
2.43M
    switch (fuzz_op) {
95
51.1k
    case FuzzOp::kPut: {
96
51.1k
      std::string key = fuzzed_data.ConsumeRandomLengthString();
97
51.1k
      std::string value = fuzzed_data.ConsumeRandomLengthString();
98
51.1k
      db->Put(leveldb::WriteOptions(), key, value);
99
51.1k
      break;
100
0
    }
101
49.3k
    case FuzzOp::kGet: {
102
49.3k
      std::string key = fuzzed_data.ConsumeRandomLengthString();
103
49.3k
      std::string value;
104
49.3k
      db->Get(leveldb::ReadOptions(), key, &value);
105
49.3k
      break;
106
0
    }
107
2.16M
    case FuzzOp::kDelete: {
108
2.16M
      std::string key = fuzzed_data.ConsumeRandomLengthString();
109
2.16M
      db->Delete(leveldb::WriteOptions(), key);
110
2.16M
      break;
111
0
    }
112
10.9k
    case FuzzOp::kGetProperty: {
113
10.9k
      std::string name = fuzzed_data.ConsumeRandomLengthString();
114
10.9k
      std::string value;
115
10.9k
      db->GetProperty(name, &value);
116
10.9k
      break;
117
0
    }
118
68.1k
    case FuzzOp::kIterate: {
119
68.1k
      std::unique_ptr<leveldb::Iterator> it(
120
68.1k
          db->NewIterator(leveldb::ReadOptions()));
121
462k
      for (it->SeekToFirst(); it->Valid(); it->Next())
122
394k
        continue;
123
68.1k
    }
124
88.6k
    case FuzzOp::kGetReleaseSnapshot: {
125
88.6k
      leveldb::ReadOptions snapshot_options;
126
88.6k
      snapshot_options.snapshot = db->GetSnapshot();
127
88.6k
      std::unique_ptr<leveldb::Iterator> it(db->NewIterator(snapshot_options));
128
88.6k
      db->ReleaseSnapshot(snapshot_options.snapshot);
129
88.6k
    }
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
35.8k
      std::string begin_key = fuzzed_data.ConsumeRandomLengthString();
141
35.8k
      std::string end_key =  fuzzed_data.ConsumeRandomLengthString();
142
35.8k
      leveldb::Slice begin_slice(begin_key);
143
35.8k
      leveldb::Slice end_slice(end_key);
144
35.8k
      db->CompactRange(&begin_slice, &end_slice);
145
35.8k
      break;
146
118k
    }
147
2.43M
    }
148
2.43M
  }
149
150
5.44k
  return 0;
151
5.44k
}