db_map_fuzzer.cc 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  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. #include <algorithm>
  6. #include <iostream>
  7. #include <map>
  8. #include <string>
  9. #include "proto/gen/db_operation.pb.h"
  10. #include "rocksdb/db.h"
  11. #include "rocksdb/file_system.h"
  12. #include "src/libfuzzer/libfuzzer_macro.h"
  13. #include "util.h"
  14. protobuf_mutator::libfuzzer::PostProcessorRegistration<DBOperations> reg = {
  15. [](DBOperations* input, unsigned int /* seed */) {
  16. const ROCKSDB_NAMESPACE::Comparator* comparator =
  17. ROCKSDB_NAMESPACE::BytewiseComparator();
  18. auto ops = input->mutable_operations();
  19. // Make sure begin <= end for DELETE_RANGE.
  20. for (DBOperation& op : *ops) {
  21. if (op.type() == OpType::DELETE_RANGE) {
  22. auto begin = op.key();
  23. auto end = op.value();
  24. if (comparator->Compare(begin, end) > 0) {
  25. std::swap(begin, end);
  26. op.set_key(begin);
  27. op.set_value(end);
  28. }
  29. }
  30. }
  31. }};
  32. // Execute randomly generated operations on both a DB and a std::map,
  33. // then reopen the DB and make sure that iterating the DB produces the
  34. // same key-value pairs as iterating through the std::map.
  35. DEFINE_PROTO_FUZZER(DBOperations& input) {
  36. if (input.operations().empty()) {
  37. return;
  38. }
  39. const std::string kDbPath = "/tmp/db_map_fuzzer_test";
  40. auto fs = ROCKSDB_NAMESPACE::FileSystem::Default();
  41. if (fs->FileExists(kDbPath, ROCKSDB_NAMESPACE::IOOptions(), /*dbg=*/nullptr)
  42. .ok()) {
  43. std::cerr << "db path " << kDbPath << " already exists" << std::endl;
  44. abort();
  45. }
  46. std::map<std::string, std::string> kv;
  47. ROCKSDB_NAMESPACE::DB* db = nullptr;
  48. ROCKSDB_NAMESPACE::Options options;
  49. options.create_if_missing = true;
  50. CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db));
  51. for (const DBOperation& op : input.operations()) {
  52. switch (op.type()) {
  53. case OpType::PUT: {
  54. CHECK_OK(
  55. db->Put(ROCKSDB_NAMESPACE::WriteOptions(), op.key(), op.value()));
  56. kv[op.key()] = op.value();
  57. break;
  58. }
  59. case OpType::MERGE: {
  60. break;
  61. }
  62. case OpType::DELETE: {
  63. CHECK_OK(db->Delete(ROCKSDB_NAMESPACE::WriteOptions(), op.key()));
  64. kv.erase(op.key());
  65. break;
  66. }
  67. case OpType::DELETE_RANGE: {
  68. // [op.key(), op.value()) corresponds to [begin, end).
  69. CHECK_OK(db->DeleteRange(ROCKSDB_NAMESPACE::WriteOptions(),
  70. db->DefaultColumnFamily(), op.key(),
  71. op.value()));
  72. kv.erase(kv.lower_bound(op.key()), kv.lower_bound(op.value()));
  73. break;
  74. }
  75. default: {
  76. std::cerr << "Unsupported operation" << static_cast<int>(op.type());
  77. return;
  78. }
  79. }
  80. }
  81. CHECK_OK(db->Close());
  82. delete db;
  83. db = nullptr;
  84. CHECK_OK(ROCKSDB_NAMESPACE::DB::Open(options, kDbPath, &db));
  85. auto kv_it = kv.begin();
  86. ROCKSDB_NAMESPACE::Iterator* it =
  87. db->NewIterator(ROCKSDB_NAMESPACE::ReadOptions());
  88. for (it->SeekToFirst(); it->Valid(); it->Next(), kv_it++) {
  89. CHECK_TRUE(kv_it != kv.end());
  90. CHECK_EQ(it->key().ToString(), kv_it->first);
  91. CHECK_EQ(it->value().ToString(), kv_it->second);
  92. }
  93. CHECK_TRUE(kv_it == kv.end());
  94. delete it;
  95. CHECK_OK(db->Close());
  96. delete db;
  97. CHECK_OK(ROCKSDB_NAMESPACE::DestroyDB(kDbPath, options));
  98. }