chunked_vector_fuzzer.cc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // Copyright 2021 gRPC authors.
  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. #include <vector>
  15. #include "src/core/lib/gprpp/chunked_vector.h"
  16. #include "src/core/lib/resource_quota/resource_quota.h"
  17. #include "src/libfuzzer/libfuzzer_macro.h"
  18. #include "test/core/gprpp/chunked_vector_fuzzer.pb.h"
  19. bool squelch = true;
  20. bool leak_check = true;
  21. static auto* g_memory_allocator = new grpc_core::MemoryAllocator(
  22. grpc_core::ResourceQuota::Default()->memory_quota()->CreateMemoryAllocator(
  23. "test"));
  24. static constexpr size_t kChunkSize = 17;
  25. using IntHdl = std::shared_ptr<int>;
  26. namespace grpc_core {
  27. struct Comparison {
  28. explicit Comparison(Arena* arena) : chunked(arena) {}
  29. ChunkedVector<IntHdl, kChunkSize> chunked;
  30. std::vector<IntHdl> std;
  31. // Check that both chunked and std are equivalent.
  32. void AssertOk() const {
  33. GPR_ASSERT(std.size() == chunked.size());
  34. auto it_chunked = chunked.cbegin();
  35. auto it_std = std.cbegin();
  36. while (it_std != std.cend()) {
  37. GPR_ASSERT(**it_std == **it_chunked);
  38. ++it_chunked;
  39. ++it_std;
  40. }
  41. GPR_ASSERT(it_chunked == chunked.cend());
  42. }
  43. };
  44. class Fuzzer {
  45. public:
  46. Fuzzer() = default;
  47. ~Fuzzer() = default;
  48. void Act(const chunked_vector_fuzzer::Action& action) {
  49. switch (action.action_type_case()) {
  50. case chunked_vector_fuzzer::Action::kEmplaceBack: {
  51. // Add some value to the back of a comparison, assert that both vectors
  52. // are equivalent.
  53. auto* c = Mutate(action.emplace_back().vector());
  54. c->chunked.EmplaceBack(
  55. std::make_shared<int>(action.emplace_back().value()));
  56. c->std.emplace_back(
  57. std::make_shared<int>(action.emplace_back().value()));
  58. c->AssertOk();
  59. } break;
  60. case chunked_vector_fuzzer::Action::kPopBack: {
  61. // Remove some value to the back of a comparison, assert that both
  62. // vectors are equivalent.
  63. auto* c = Mutate(action.pop_back().vector());
  64. if (!c->chunked.empty()) {
  65. c->chunked.PopBack();
  66. c->std.pop_back();
  67. c->AssertOk();
  68. }
  69. } break;
  70. case chunked_vector_fuzzer::Action::kCopy: {
  71. // Copy one vector into another, assert both everything stays
  72. // equivalent.
  73. auto it_from = vectors_.find(action.copy().from());
  74. if (it_from == vectors_.end()) {
  75. it_from =
  76. vectors_.emplace(action.copy().from(), Comparison(arena_.get()))
  77. .first;
  78. }
  79. auto it_to = vectors_.find(action.copy().to());
  80. if (it_to == vectors_.end()) {
  81. it_to = vectors_.emplace(action.copy().to(), it_from->second).first;
  82. } else {
  83. it_to->second = it_from->second;
  84. }
  85. it_from->second.AssertOk();
  86. it_to->second.AssertOk();
  87. } break;
  88. case chunked_vector_fuzzer::Action::kMove: {
  89. // Move one vector into another, assert both everything stays
  90. // equivalent.
  91. auto it_from = vectors_.find(action.move().from());
  92. if (it_from == vectors_.end()) {
  93. it_from =
  94. vectors_.emplace(action.move().from(), Comparison(arena_.get()))
  95. .first;
  96. }
  97. auto it_to = vectors_.find(action.move().to());
  98. if (it_to == vectors_.end()) {
  99. it_to =
  100. vectors_.emplace(action.move().to(), std::move(it_from->second))
  101. .first;
  102. } else {
  103. it_to->second = it_from->second;
  104. }
  105. it_from->second.AssertOk();
  106. it_to->second.AssertOk();
  107. } break;
  108. case chunked_vector_fuzzer::Action::kClear: {
  109. // Clear a vector, assert that both underlying vectors are equivalent.
  110. auto* c = Mutate(action.clear().vector());
  111. c->chunked.Clear();
  112. c->std.clear();
  113. c->AssertOk();
  114. } break;
  115. case chunked_vector_fuzzer::Action::kSwap: {
  116. // Swap two vectors, assert that both underlying vectors are equivalent.
  117. auto* from = Mutate(action.swap().from());
  118. auto* to = Mutate(action.swap().to());
  119. from->chunked.Swap(&to->chunked);
  120. from->std.swap(to->std);
  121. from->AssertOk();
  122. } break;
  123. case chunked_vector_fuzzer::Action::kRemoveIf: {
  124. // Apply std::remove_if to a vector, assert that underlying vectors
  125. // remain equivalent.
  126. auto cond = [&](const IntHdl& hdl) {
  127. return *hdl == action.remove_if().value();
  128. };
  129. auto* c = Mutate(action.remove_if().vector());
  130. c->chunked.SetEnd(
  131. std::remove_if(c->chunked.begin(), c->chunked.end(), cond));
  132. c->std.erase(std::remove_if(c->std.begin(), c->std.end(), cond),
  133. c->std.end());
  134. c->AssertOk();
  135. } break;
  136. case chunked_vector_fuzzer::Action::ACTION_TYPE_NOT_SET:
  137. break;
  138. }
  139. }
  140. private:
  141. Comparison* Mutate(int index) {
  142. auto it = vectors_.find(index);
  143. if (it != vectors_.end()) {
  144. return &it->second;
  145. }
  146. return &vectors_.emplace(index, Comparison(arena_.get())).first->second;
  147. }
  148. ScopedArenaPtr arena_ = MakeScopedArena(128, g_memory_allocator);
  149. std::map<int, Comparison> vectors_;
  150. };
  151. } // namespace grpc_core
  152. DEFINE_PROTO_FUZZER(const chunked_vector_fuzzer::Msg& msg) {
  153. grpc_core::Fuzzer fuzzer;
  154. for (int i = 0; i < msg.actions_size(); i++) {
  155. fuzzer.Act(msg.actions(i));
  156. }
  157. }