promise_fuzzer.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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 "src/core/lib/promise/activity.h"
  15. #include "src/core/lib/promise/join.h"
  16. #include "src/core/lib/promise/map.h"
  17. #include "src/core/lib/promise/promise.h"
  18. #include "src/core/lib/promise/race.h"
  19. #include "src/core/lib/promise/seq.h"
  20. #include "src/libfuzzer/libfuzzer_macro.h"
  21. #include "test/core/promise/promise_fuzzer.pb.h"
  22. bool squelch = true;
  23. bool leak_check = true;
  24. namespace grpc_core {
  25. // Return type for infallible promises.
  26. // We choose this so that it's easy to construct, and will trigger asan failures
  27. // if misused, and is copyable.
  28. using IntHdl = std::shared_ptr<int>;
  29. template <typename T>
  30. using PromiseFactory = std::function<Promise<T>(T)>;
  31. namespace {
  32. class Fuzzer {
  33. public:
  34. void Run(const promise_fuzzer::Msg& msg) {
  35. // If there's no promise we can't construct and activity and... we're done.
  36. if (!msg.has_promise()) {
  37. return;
  38. }
  39. // Construct activity.
  40. activity_ = MakeActivity(
  41. [msg, this] {
  42. return Seq(MakePromise(msg.promise()),
  43. [] { return absl::OkStatus(); });
  44. },
  45. Scheduler{this},
  46. [this](absl::Status status) {
  47. // Must only be called once
  48. GPR_ASSERT(!done_);
  49. // If we became certain of the eventual status, verify it.
  50. if (expected_status_.has_value()) {
  51. GPR_ASSERT(status == *expected_status_);
  52. }
  53. // Mark ourselves done.
  54. done_ = true;
  55. });
  56. for (int i = 0; !done_ && activity_ != nullptr && i < msg.actions_size();
  57. i++) {
  58. // Do some things
  59. const auto& action = msg.actions(i);
  60. switch (action.action_type_case()) {
  61. // Force a wakeup
  62. case promise_fuzzer::Action::kForceWakeup:
  63. activity_->ForceWakeup();
  64. break;
  65. // Cancel from the outside
  66. case promise_fuzzer::Action::kCancel:
  67. ExpectCancelled();
  68. activity_.reset();
  69. break;
  70. // Flush any pending wakeups
  71. case promise_fuzzer::Action::kFlushWakeup:
  72. if (wakeup_ != nullptr) absl::exchange(wakeup_, nullptr)();
  73. break;
  74. // Drop some wakeups (external system closed?)
  75. case promise_fuzzer::Action::kDropWaker: {
  76. int n = action.drop_waker();
  77. auto v = std::move(wakers_[n]);
  78. wakers_.erase(n);
  79. break;
  80. }
  81. // Wakeup some wakeups
  82. case promise_fuzzer::Action::kAwakeWaker: {
  83. int n = action.awake_waker();
  84. auto v = std::move(wakers_[n]);
  85. wakers_.erase(n);
  86. for (auto& w : v) {
  87. w.Wakeup();
  88. }
  89. break;
  90. }
  91. case promise_fuzzer::Action::ACTION_TYPE_NOT_SET:
  92. break;
  93. }
  94. }
  95. ExpectCancelled();
  96. activity_.reset();
  97. if (wakeup_ != nullptr) absl::exchange(wakeup_, nullptr)();
  98. GPR_ASSERT(done_);
  99. }
  100. private:
  101. // Schedule wakeups against the fuzzer
  102. struct Scheduler {
  103. Fuzzer* fuzzer;
  104. // Schedule a wakeup
  105. template <typename ActivityType>
  106. void ScheduleWakeup(ActivityType* activity) {
  107. GPR_ASSERT(activity == fuzzer->activity_.get());
  108. GPR_ASSERT(fuzzer->wakeup_ == nullptr);
  109. fuzzer->wakeup_ = [activity]() { activity->RunScheduledWakeup(); };
  110. }
  111. };
  112. // We know that if not already finished, the status when finished will be
  113. // cancelled.
  114. void ExpectCancelled() {
  115. if (!done_ && !expected_status_.has_value()) {
  116. expected_status_ = absl::CancelledError();
  117. }
  118. }
  119. // Construct a promise factory from a protobuf
  120. PromiseFactory<IntHdl> MakePromiseFactory(
  121. const promise_fuzzer::PromiseFactory& p) {
  122. switch (p.promise_factory_type_case()) {
  123. case promise_fuzzer::PromiseFactory::kPromise:
  124. return [p, this](IntHdl) { return MakePromise(p.promise()); };
  125. case promise_fuzzer::PromiseFactory::kLast:
  126. return [](IntHdl h) { return [h]() { return h; }; };
  127. case promise_fuzzer::PromiseFactory::PROMISE_FACTORY_TYPE_NOT_SET:
  128. break;
  129. }
  130. return [](IntHdl) {
  131. return []() -> Poll<IntHdl> { return std::make_shared<int>(42); };
  132. };
  133. }
  134. // Construct a promise from a protobuf
  135. Promise<IntHdl> MakePromise(const promise_fuzzer::Promise& p) {
  136. switch (p.promise_type_case()) {
  137. case promise_fuzzer::Promise::kSeq:
  138. switch (p.seq().promise_factories_size()) {
  139. case 1:
  140. return Seq(MakePromise(p.seq().first()),
  141. MakePromiseFactory(p.seq().promise_factories(0)));
  142. case 2:
  143. return Seq(MakePromise(p.seq().first()),
  144. MakePromiseFactory(p.seq().promise_factories(0)),
  145. MakePromiseFactory(p.seq().promise_factories(1)));
  146. case 3:
  147. return Seq(MakePromise(p.seq().first()),
  148. MakePromiseFactory(p.seq().promise_factories(0)),
  149. MakePromiseFactory(p.seq().promise_factories(1)),
  150. MakePromiseFactory(p.seq().promise_factories(2)));
  151. case 4:
  152. return Seq(MakePromise(p.seq().first()),
  153. MakePromiseFactory(p.seq().promise_factories(0)),
  154. MakePromiseFactory(p.seq().promise_factories(1)),
  155. MakePromiseFactory(p.seq().promise_factories(2)),
  156. MakePromiseFactory(p.seq().promise_factories(3)));
  157. case 5:
  158. return Seq(MakePromise(p.seq().first()),
  159. MakePromiseFactory(p.seq().promise_factories(0)),
  160. MakePromiseFactory(p.seq().promise_factories(1)),
  161. MakePromiseFactory(p.seq().promise_factories(2)),
  162. MakePromiseFactory(p.seq().promise_factories(3)),
  163. MakePromiseFactory(p.seq().promise_factories(4)));
  164. case 6:
  165. return Seq(MakePromise(p.seq().first()),
  166. MakePromiseFactory(p.seq().promise_factories(0)),
  167. MakePromiseFactory(p.seq().promise_factories(1)),
  168. MakePromiseFactory(p.seq().promise_factories(2)),
  169. MakePromiseFactory(p.seq().promise_factories(3)),
  170. MakePromiseFactory(p.seq().promise_factories(4)),
  171. MakePromiseFactory(p.seq().promise_factories(5)));
  172. }
  173. break;
  174. case promise_fuzzer::Promise::kJoin:
  175. switch (p.join().promises_size()) {
  176. case 1:
  177. return Map(Join(MakePromise(p.join().promises(0))),
  178. [](std::tuple<IntHdl> t) { return std::get<0>(t); });
  179. case 2:
  180. return Map(
  181. Join(MakePromise(p.join().promises(0)),
  182. MakePromise(p.join().promises(1))),
  183. [](std::tuple<IntHdl, IntHdl> t) { return std::get<0>(t); });
  184. case 3:
  185. return Map(Join(MakePromise(p.join().promises(0)),
  186. MakePromise(p.join().promises(1)),
  187. MakePromise(p.join().promises(2))),
  188. [](std::tuple<IntHdl, IntHdl, IntHdl> t) {
  189. return std::get<0>(t);
  190. });
  191. case 4:
  192. return Map(Join(MakePromise(p.join().promises(0)),
  193. MakePromise(p.join().promises(1)),
  194. MakePromise(p.join().promises(2)),
  195. MakePromise(p.join().promises(3))),
  196. [](std::tuple<IntHdl, IntHdl, IntHdl, IntHdl> t) {
  197. return std::get<0>(t);
  198. });
  199. case 5:
  200. return Map(
  201. Join(MakePromise(p.join().promises(0)),
  202. MakePromise(p.join().promises(1)),
  203. MakePromise(p.join().promises(2)),
  204. MakePromise(p.join().promises(3)),
  205. MakePromise(p.join().promises(4))),
  206. [](std::tuple<IntHdl, IntHdl, IntHdl, IntHdl, IntHdl> t) {
  207. return std::get<0>(t);
  208. });
  209. case 6:
  210. return Map(
  211. Join(MakePromise(p.join().promises(0)),
  212. MakePromise(p.join().promises(1)),
  213. MakePromise(p.join().promises(2)),
  214. MakePromise(p.join().promises(3)),
  215. MakePromise(p.join().promises(4)),
  216. MakePromise(p.join().promises(5))),
  217. [](std::tuple<IntHdl, IntHdl, IntHdl, IntHdl, IntHdl, IntHdl>
  218. t) { return std::get<0>(t); });
  219. }
  220. break;
  221. case promise_fuzzer::Promise::kRace:
  222. switch (p.race().promises_size()) {
  223. case 1:
  224. return Race(MakePromise(p.race().promises(0)));
  225. case 2:
  226. return Race(MakePromise(p.race().promises(0)),
  227. MakePromise(p.race().promises(1)));
  228. case 3:
  229. return Race(MakePromise(p.race().promises(0)),
  230. MakePromise(p.race().promises(1)),
  231. MakePromise(p.race().promises(2)));
  232. case 4:
  233. return Race(MakePromise(p.race().promises(0)),
  234. MakePromise(p.race().promises(1)),
  235. MakePromise(p.race().promises(2)),
  236. MakePromise(p.race().promises(3)));
  237. case 5:
  238. return Race(MakePromise(p.race().promises(0)),
  239. MakePromise(p.race().promises(1)),
  240. MakePromise(p.race().promises(2)),
  241. MakePromise(p.race().promises(3)),
  242. MakePromise(p.race().promises(4)));
  243. case 6:
  244. return Race(MakePromise(p.race().promises(0)),
  245. MakePromise(p.race().promises(1)),
  246. MakePromise(p.race().promises(2)),
  247. MakePromise(p.race().promises(3)),
  248. MakePromise(p.race().promises(4)),
  249. MakePromise(p.race().promises(5)));
  250. }
  251. break;
  252. case promise_fuzzer::Promise::kNever:
  253. return Never<IntHdl>();
  254. case promise_fuzzer::Promise::kSleepFirstN: {
  255. int n = p.sleep_first_n();
  256. return [n]() mutable -> Poll<IntHdl> {
  257. if (n <= 0) return std::make_shared<int>(0);
  258. n--;
  259. return Pending{};
  260. };
  261. }
  262. case promise_fuzzer::Promise::kCancelFromInside:
  263. return [this]() -> Poll<IntHdl> {
  264. this->activity_.reset();
  265. return Pending{};
  266. };
  267. case promise_fuzzer::Promise::kWaitOnceOnWaker: {
  268. bool called = false;
  269. auto config = p.wait_once_on_waker();
  270. return [this, config, called]() mutable -> Poll<IntHdl> {
  271. if (!called) {
  272. if (config.owning()) {
  273. wakers_[config.waker()].push_back(
  274. Activity::current()->MakeOwningWaker());
  275. } else {
  276. wakers_[config.waker()].push_back(
  277. Activity::current()->MakeNonOwningWaker());
  278. }
  279. return Pending();
  280. }
  281. return std::make_shared<int>(3);
  282. };
  283. }
  284. case promise_fuzzer::Promise::PromiseTypeCase::PROMISE_TYPE_NOT_SET:
  285. break;
  286. }
  287. return [] { return std::make_shared<int>(42); };
  288. }
  289. // Activity under test
  290. ActivityPtr activity_;
  291. // Scheduled wakeup (may be nullptr if no wakeup scheduled)
  292. std::function<void()> wakeup_;
  293. // If we are certain of the final status, then that. Otherwise, nullopt if we
  294. // don't know.
  295. absl::optional<absl::Status> expected_status_;
  296. // Has on_done been called?
  297. bool done_ = false;
  298. // Wakers that may be scheduled
  299. std::map<int, std::vector<Waker>> wakers_;
  300. };
  301. } // namespace
  302. } // namespace grpc_core
  303. DEFINE_PROTO_FUZZER(const promise_fuzzer::Msg& msg) {
  304. grpc_core::Fuzzer().Run(msg);
  305. }