Coverage Report

Created: 2024-07-27 06:53

/src/rocksdb/fuzz/db_map_fuzzer.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
// This source code is licensed under both the GPLv2 (found in the
3
// COPYING file in the root directory) and Apache 2.0 License
4
// (found in the LICENSE.Apache file in the root directory).
5
6
#include <algorithm>
7
#include <iostream>
8
#include <map>
9
#include <string>
10
11
#include "proto/gen/db_operation.pb.h"
12
#include "rocksdb/db.h"
13
#include "rocksdb/file_system.h"
14
#include "src/libfuzzer/libfuzzer_macro.h"
15
#include "util.h"
16
17
protobuf_mutator::libfuzzer::PostProcessorRegistration<DBOperations> reg = {
18
4.51k
    [](DBOperations* input, unsigned int /* seed */) {
19
4.51k
      const ROCKSDB_NAMESPACE::Comparator* comparator =
20
4.51k
          ROCKSDB_NAMESPACE::BytewiseComparator();
21
4.51k
      auto ops = input->mutable_operations();
22
      // Make sure begin <= end for DELETE_RANGE.
23
1.56M
      for (DBOperation& op : *ops) {
24
1.56M
        if (op.type() == OpType::DELETE_RANGE) {
25
515k
          auto begin = op.key();
26
515k
          auto end = op.value();
27
515k
          if (comparator->Compare(begin, end) > 0) {
28
2.14k
            std::swap(begin, end);
29
2.14k
            op.set_key(begin);
30
2.14k
            op.set_value(end);
31
2.14k
          }
32
515k
        }
33
1.56M
      }
34
4.51k
    }};
35
36
// Execute randomly generated operations on both a DB and a std::map,
37
// then reopen the DB and make sure that iterating the DB produces the
38
// same key-value pairs as iterating through the std::map.
39
4.51k
DEFINE_PROTO_FUZZER(DBOperations& input) {
40
4.51k
  if (input.operations().empty()) {
41
3
    return;
42
3
  }
43
44
4.51k
  const std::string kDbPath = "/tmp/db_map_fuzzer_test";
45
4.51k
  auto fs = ROCKSDB_NAMESPACE::FileSystem::Default();
46
4.51k
  if (fs->FileExists(kDbPath, ROCKSDB_NAMESPACE::IOOptions(), /*dbg=*/nullptr)
47
4.51k
          .ok()) {
48
0
    std::cerr << "db path " << kDbPath << " already exists" << std::endl;
49
0
    abort();
50
0
  }
51
52
4.51k
  std::map<std::string, std::string> kv;
53
4.51k
  ROCKSDB_NAMESPACE::DB* db = nullptr;
54
4.51k
  ROCKSDB_NAMESPACE::Options options;
55
4.51k
  options.create_if_missing = true;
56
4.51k
  CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db));
57
58
1.56M
  for (const DBOperation& op : input.operations()) {
59
1.56M
    switch (op.type()) {
60
660k
      case OpType::PUT: {
61
660k
        CHECK_OK(
62
660k
            db->Put(ROCKSDB_NAMESPACE::WriteOptions(), op.key(), op.value()));
63
660k
        kv[op.key()] = op.value();
64
660k
        break;
65
660k
      }
66
200k
      case OpType::MERGE: {
67
200k
        break;
68
660k
      }
69
186k
      case OpType::DELETE: {
70
186k
        CHECK_OK(db->Delete(ROCKSDB_NAMESPACE::WriteOptions(), op.key()));
71
186k
        kv.erase(op.key());
72
186k
        break;
73
186k
      }
74
515k
      case OpType::DELETE_RANGE: {
75
        // [op.key(), op.value()) corresponds to [begin, end).
76
515k
        CHECK_OK(db->DeleteRange(ROCKSDB_NAMESPACE::WriteOptions(),
77
515k
                                 db->DefaultColumnFamily(), op.key(),
78
515k
                                 op.value()));
79
515k
        kv.erase(kv.lower_bound(op.key()), kv.lower_bound(op.value()));
80
515k
        break;
81
515k
      }
82
0
      default: {
83
0
        std::cerr << "Unsupported operation" << static_cast<int>(op.type());
84
0
        return;
85
515k
      }
86
1.56M
    }
87
1.56M
  }
88
4.51k
  CHECK_OK(db->Close());
89
4.51k
  delete db;
90
4.51k
  db = nullptr;
91
92
4.51k
  CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db));
93
4.51k
  auto kv_it = kv.begin();
94
4.51k
  ROCKSDB_NAMESPACE::Iterator* it =
95
4.51k
      db->NewIterator(ROCKSDB_NAMESPACE::ReadOptions());
96
34.1k
  for (it->SeekToFirst(); it->Valid(); it->Next(), kv_it++) {
97
29.5k
    CHECK_TRUE(kv_it != kv.end());
98
29.5k
    CHECK_EQ(it->key().ToString(), kv_it->first);
99
29.5k
    CHECK_EQ(it->value().ToString(), kv_it->second);
100
29.5k
  }
101
4.51k
  CHECK_TRUE(kv_it == kv.end());
102
4.51k
  delete it;
103
104
4.51k
  CHECK_OK(db->Close());
105
4.51k
  delete db;
106
4.51k
  CHECK_OK(ROCKSDB_NAMESPACE::DestroyDB(kDbPath, options));
107
4.51k
}