db_fuzzer.cc 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Copyright (c) Meta Platforms, Inc. and affiliates.
  2. //
  3. // This source code is licensed under both the GPLv2 (found in the
  4. // COPYING file in the root directory) and Apache 2.0 License
  5. // (found in the LICENSE.Apache file in the root directory).
  6. #include <fuzzer/FuzzedDataProvider.h>
  7. #include "rocksdb/db.h"
  8. enum OperationType {
  9. kPut,
  10. kGet,
  11. kDelete,
  12. kGetProperty,
  13. kIterator,
  14. kSnapshot,
  15. kOpenClose,
  16. kColumn,
  17. kCompactRange,
  18. kSeekForPrev,
  19. OP_COUNT
  20. };
  21. constexpr char db_path[] = "/tmp/testdb";
  22. // Fuzzes DB operations by doing interpretations on the data. Both the
  23. // sequence of API calls to be called on the DB as well as the arguments
  24. // to each of these APIs are interpreted by way of the data buffer.
  25. // The operations that the fuzzer supports are given by the OperationType
  26. // enum. The goal is to capture sanitizer bugs, so the code should be
  27. // compiled with a given sanitizer (ASan, UBSan, MSan).
  28. extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  29. ROCKSDB_NAMESPACE::DB* db;
  30. ROCKSDB_NAMESPACE::Options options;
  31. options.create_if_missing = true;
  32. ROCKSDB_NAMESPACE::Status status =
  33. ROCKSDB_NAMESPACE::DB::Open(options, db_path, &db);
  34. if (!status.ok()) {
  35. return 0;
  36. }
  37. FuzzedDataProvider fuzzed_data(data, size);
  38. // perform a sequence of calls on our db instance
  39. int max_iter = static_cast<int>(data[0]);
  40. for (int i = 0; i < max_iter && i < size; i++) {
  41. OperationType op = static_cast<OperationType>(data[i] % OP_COUNT);
  42. switch (op) {
  43. case kPut: {
  44. std::string key = fuzzed_data.ConsumeRandomLengthString();
  45. std::string val = fuzzed_data.ConsumeRandomLengthString();
  46. db->Put(ROCKSDB_NAMESPACE::WriteOptions(), key, val);
  47. break;
  48. }
  49. case kGet: {
  50. std::string key = fuzzed_data.ConsumeRandomLengthString();
  51. std::string value;
  52. db->Get(ROCKSDB_NAMESPACE::ReadOptions(), key, &value);
  53. break;
  54. }
  55. case kDelete: {
  56. std::string key = fuzzed_data.ConsumeRandomLengthString();
  57. db->Delete(ROCKSDB_NAMESPACE::WriteOptions(), key);
  58. break;
  59. }
  60. case kGetProperty: {
  61. std::string prop;
  62. std::string property_name = fuzzed_data.ConsumeRandomLengthString();
  63. db->GetProperty(property_name, &prop);
  64. break;
  65. }
  66. case kIterator: {
  67. ROCKSDB_NAMESPACE::Iterator* it =
  68. db->NewIterator(ROCKSDB_NAMESPACE::ReadOptions());
  69. for (it->SeekToFirst(); it->Valid(); it->Next()) {
  70. }
  71. delete it;
  72. break;
  73. }
  74. case kSnapshot: {
  75. ROCKSDB_NAMESPACE::ReadOptions snapshot_options;
  76. snapshot_options.snapshot = db->GetSnapshot();
  77. ROCKSDB_NAMESPACE::Iterator* it = db->NewIterator(snapshot_options);
  78. db->ReleaseSnapshot(snapshot_options.snapshot);
  79. delete it;
  80. break;
  81. }
  82. case kOpenClose: {
  83. db->Close();
  84. delete db;
  85. status = ROCKSDB_NAMESPACE::DB::Open(options, db_path, &db);
  86. if (!status.ok()) {
  87. ROCKSDB_NAMESPACE::DestroyDB(db_path, options);
  88. return 0;
  89. }
  90. break;
  91. }
  92. case kColumn: {
  93. ROCKSDB_NAMESPACE::ColumnFamilyHandle* cf;
  94. ROCKSDB_NAMESPACE::Status s;
  95. s = db->CreateColumnFamily(ROCKSDB_NAMESPACE::ColumnFamilyOptions(),
  96. "new_cf", &cf);
  97. s = db->DestroyColumnFamilyHandle(cf);
  98. db->Close();
  99. delete db;
  100. // open DB with two column families
  101. std::vector<ROCKSDB_NAMESPACE::ColumnFamilyDescriptor> column_families;
  102. // have to open default column family
  103. column_families.push_back(ROCKSDB_NAMESPACE::ColumnFamilyDescriptor(
  104. ROCKSDB_NAMESPACE::kDefaultColumnFamilyName,
  105. ROCKSDB_NAMESPACE::ColumnFamilyOptions()));
  106. // open the new one, too
  107. column_families.push_back(ROCKSDB_NAMESPACE::ColumnFamilyDescriptor(
  108. "new_cf", ROCKSDB_NAMESPACE::ColumnFamilyOptions()));
  109. std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*> handles;
  110. s = ROCKSDB_NAMESPACE::DB::Open(ROCKSDB_NAMESPACE::DBOptions(), db_path,
  111. column_families, &handles, &db);
  112. if (s.ok()) {
  113. std::string key1 = fuzzed_data.ConsumeRandomLengthString();
  114. std::string val1 = fuzzed_data.ConsumeRandomLengthString();
  115. std::string key2 = fuzzed_data.ConsumeRandomLengthString();
  116. s = db->Put(ROCKSDB_NAMESPACE::WriteOptions(), handles[1], key1,
  117. val1);
  118. std::string value;
  119. s = db->Get(ROCKSDB_NAMESPACE::ReadOptions(), handles[1], key2,
  120. &value);
  121. s = db->DropColumnFamily(handles[1]);
  122. for (auto handle : handles) {
  123. s = db->DestroyColumnFamilyHandle(handle);
  124. }
  125. } else {
  126. status = ROCKSDB_NAMESPACE::DB::Open(options, db_path, &db);
  127. if (!status.ok()) {
  128. // At this point there is no saving to do. So we exit
  129. ROCKSDB_NAMESPACE::DestroyDB(db_path, ROCKSDB_NAMESPACE::Options());
  130. return 0;
  131. }
  132. }
  133. break;
  134. }
  135. case kCompactRange: {
  136. std::string slice_start = fuzzed_data.ConsumeRandomLengthString();
  137. std::string slice_end = fuzzed_data.ConsumeRandomLengthString();
  138. ROCKSDB_NAMESPACE::Slice begin(slice_start);
  139. ROCKSDB_NAMESPACE::Slice end(slice_end);
  140. ROCKSDB_NAMESPACE::CompactRangeOptions options;
  141. ROCKSDB_NAMESPACE::Status s = db->CompactRange(options, &begin, &end);
  142. break;
  143. }
  144. case kSeekForPrev: {
  145. std::string key = fuzzed_data.ConsumeRandomLengthString();
  146. auto iter = db->NewIterator(ROCKSDB_NAMESPACE::ReadOptions());
  147. iter->SeekForPrev(key);
  148. delete iter;
  149. break;
  150. }
  151. case OP_COUNT:
  152. break;
  153. }
  154. }
  155. // Cleanup DB
  156. db->Close();
  157. delete db;
  158. ROCKSDB_NAMESPACE::DestroyDB(db_path, options);
  159. return 0;
  160. }