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


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:46