urandom_test.cc
Go to the documentation of this file.
1 /* Copyright (c) 2019, Google Inc.
2  *
3  * Permission to use, copy, modify, and/or distribute this software for any
4  * purpose with or without fee is hereby granted, provided that the above
5  * copyright notice and this permission notice appear in all copies.
6  *
7  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10  * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14 
15 #include <gtest/gtest.h>
16 #include <stdlib.h>
17 
18 #include <openssl/rand.h>
19 
20 #include "internal.h"
21 #include "getrandom_fillin.h"
22 
23 #if defined(OPENSSL_X86_64) && !defined(BORINGSSL_SHARED_LIBRARY) && \
24  !defined(BORINGSSL_UNSAFE_DETERMINISTIC_MODE) && defined(USE_NR_getrandom)
25 
26 #include <linux/random.h>
27 #include <sys/ptrace.h>
28 #include <sys/syscall.h>
29 #include <sys/user.h>
30 
31 #include "fork_detect.h"
32 
33 #if !defined(PTRACE_O_EXITKILL)
34 #define PTRACE_O_EXITKILL (1 << 20)
35 #endif
36 
37 // This test can be run with $OPENSSL_ia32cap=~0x4000000000000000 in order to
38 // simulate the absence of RDRAND of machines that have it.
39 
40 // Event represents a system call from urandom.c that is observed by the ptrace
41 // code in |GetTrace|.
42 struct Event {
43  enum class Syscall {
44  kGetRandom,
45  kOpen,
46  kUrandomRead,
47  kUrandomIoctl,
48  kAbort,
49  };
50 
51  explicit Event(Syscall syscall) : type(syscall) {}
52 
53  bool operator==(const Event &other) const {
54  return type == other.type && length == other.length &&
55  flags == other.flags &&
56  ((filename == nullptr && other.filename == nullptr) ||
57  strcmp(filename, other.filename) == 0);
58  }
59 
60  static Event GetRandom(size_t length, unsigned flags) {
61  Event e(Syscall::kGetRandom);
62  e.length = length;
63  e.flags = flags;
64  return e;
65  }
66 
67  static Event Open(const char *filename) {
68  Event e(Syscall::kOpen);
69  e.filename = filename;
70  return e;
71  }
72 
73  static Event UrandomRead(size_t length) {
74  Event e(Syscall::kUrandomRead);
75  e.length = length;
76  return e;
77  }
78 
79  static Event UrandomIoctl() {
80  Event e(Syscall::kUrandomIoctl);
81  return e;
82  }
83 
84  static Event Abort() {
85  Event e(Syscall::kAbort);
86  return e;
87  }
88 
89  std::string String() const {
90  char buf[256];
91 
92  switch (type) {
93  case Syscall::kGetRandom:
94  snprintf(buf, sizeof(buf), "getrandom(_, %zu, %d)", length, flags);
95  break;
96 
97  case Syscall::kOpen:
98  snprintf(buf, sizeof(buf), "open(%s, _)", filename);
99  break;
100 
101  case Syscall::kUrandomRead:
102  snprintf(buf, sizeof(buf), "read(urandom_fd, _, %zu)", length);
103  break;
104 
105  case Syscall::kUrandomIoctl:
106  return "ioctl(urandom_fd, RNDGETENTCNT, _)";
107 
108  case Syscall::kAbort:
109  return "abort()";
110  }
111 
112  return std::string(buf);
113  }
114 
115  const Syscall type;
116  size_t length = 0;
117  unsigned flags = 0;
118  const char *filename = nullptr;
119 };
120 
121 static std::string ToString(const std::vector<Event> &trace) {
123  for (const auto &event : trace) {
124  if (!ret.empty()) {
125  ret += ", ";
126  }
127  ret += event.String();
128  }
129  return ret;
130 }
131 
132 // The following are flags to tell |GetTrace| to inject faults, using ptrace,
133 // into the entropy-related system calls.
134 
135 // getrandom gives |ENOSYS|.
136 static const unsigned NO_GETRANDOM = 1;
137 // opening /dev/urandom fails.
138 static const unsigned NO_URANDOM = 2;
139 // getrandom always returns |EAGAIN| if given |GRNG_NONBLOCK|.
140 static const unsigned GETRANDOM_NOT_READY = 4;
141 // The ioctl on urandom returns only 255 bits of entropy the first time that
142 // it's called.
143 static const unsigned URANDOM_NOT_READY = 8;
144 // getrandom gives |EINVAL| unless |NO_GETRANDOM| is set.
145 static const unsigned GETRANDOM_ERROR = 16;
146 // Reading from /dev/urandom gives |EINVAL|.
147 static const unsigned URANDOM_ERROR = 32;
148 static const unsigned NEXT_FLAG = 64;
149 
150 // GetTrace runs |thunk| in a forked process and observes the resulting system
151 // calls using ptrace. It simulates a variety of failures based on the contents
152 // of |flags| and records the observed events by appending to |out_trace|.
153 static void GetTrace(std::vector<Event> *out_trace, unsigned flags,
154  std::function<void()> thunk) {
155  const int child_pid = fork();
156  ASSERT_NE(-1, child_pid);
157 
158  if (child_pid == 0) {
159  // Child process
160  if (ptrace(PTRACE_TRACEME, 0, 0, 0) != 0) {
161  perror("PTRACE_TRACEME");
162  _exit(1);
163  }
164  raise(SIGSTOP);
165  thunk();
166  _exit(0);
167  }
168 
169  // Parent process
170  int status;
171  ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
172  ASSERT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == SIGSTOP);
173 
174  // Set options so that:
175  // a) the child process is killed once this process dies.
176  // b) System calls result in a WSTOPSIG value of (SIGTRAP | 0x80) rather
177  // than just SIGTRAP. (This doesn't matter here, but it's recommended
178  // practice so that it's distinct from the signal itself.)
179  ASSERT_EQ(0, ptrace(PTRACE_SETOPTIONS, child_pid, nullptr,
180  PTRACE_O_EXITKILL | PTRACE_O_TRACESYSGOOD))
181  << strerror(errno);
182 
183  // urandom_fd tracks the file descriptor number for /dev/urandom in the child
184  // process, if it opens it.
185  int urandom_fd = -1;
186 
187  for (;;) {
188  // Advance the child to the next system call.
189  ASSERT_EQ(0, ptrace(PTRACE_SYSCALL, child_pid, 0, 0));
190  ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
191 
192  // The child may have aborted rather than made a system call.
193  if (WIFSTOPPED(status) && WSTOPSIG(status) == SIGABRT) {
194  out_trace->push_back(Event::Abort());
195  break;
196  }
197 
198  // Otherwise the only valid ptrace event is a system call stop.
199  ASSERT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80));
200 
201  struct user_regs_struct regs;
202  ASSERT_EQ(0, ptrace(PTRACE_GETREGS, child_pid, nullptr, &regs));
203  const auto syscall_number = regs.orig_rax;
204 
205  bool is_opening_urandom = false;
206  bool is_urandom_ioctl = false;
207  uintptr_t ioctl_output_addr = 0;
208  // inject_error is zero to indicate that the system call should run
209  // normally. Otherwise it's, e.g. -EINVAL, to indicate that the system call
210  // should not run and that error should be injected on return.
211  int inject_error = 0;
212 
213  switch (syscall_number) {
214  case __NR_getrandom:
215  if (flags & NO_GETRANDOM) {
216  inject_error = -ENOSYS;
217  } else if (flags & GETRANDOM_ERROR) {
218  inject_error = -EINVAL;
219  } else if (flags & GETRANDOM_NOT_READY) {
220  if (regs.rdx & GRND_NONBLOCK) {
221  inject_error = -EAGAIN;
222  }
223  }
224  out_trace->push_back(
225  Event::GetRandom(/*length=*/regs.rsi, /*flags=*/regs.rdx));
226  break;
227 
228  case __NR_openat:
229  case __NR_open: {
230  // It's assumed that any arguments to open(2) are constants in read-only
231  // memory and thus the pointer in the child's context will also be a
232  // valid pointer in our address space.
233  const char *filename = reinterpret_cast<const char *>(
234  (syscall_number == __NR_openat) ? regs.rsi : regs.rdi);
235  out_trace->push_back(Event::Open(filename));
236  is_opening_urandom = strcmp(filename, "/dev/urandom") == 0;
237  if (is_opening_urandom && (flags & NO_URANDOM)) {
238  inject_error = -ENOENT;
239  }
240  break;
241  }
242 
243  case __NR_read: {
244  const int read_fd = regs.rdi;
245  if (urandom_fd >= 0 && urandom_fd == read_fd) {
246  out_trace->push_back(Event::UrandomRead(/*length=*/regs.rdx));
247  if (flags & URANDOM_ERROR) {
248  inject_error = -EINVAL;
249  }
250  }
251  break;
252  }
253 
254  case __NR_ioctl: {
255  const int ioctl_fd = regs.rdi;
256  if (urandom_fd >= 0 && ioctl_fd == urandom_fd &&
257  regs.rsi == RNDGETENTCNT) {
258  out_trace->push_back(Event::UrandomIoctl());
259  is_urandom_ioctl = true;
260  ioctl_output_addr = regs.rdx;
261  }
262  }
263  }
264 
265  if (inject_error) {
266  // Replace the system call number with -1 to cause the kernel to ignore
267  // the call. The -ENOSYS will be replaced later with the value of
268  // |inject_error|.
269  regs.orig_rax = -1;
270  ASSERT_EQ(0, ptrace(PTRACE_SETREGS, child_pid, nullptr, &regs));
271  }
272 
273  ASSERT_EQ(0, ptrace(PTRACE_SYSCALL, child_pid, 0, 0));
274  ASSERT_EQ(child_pid, waitpid(child_pid, &status, 0));
275  // If the system call was exit/exit_group, the process may be terminated
276  // rather than have exited the system call.
277  if (WIFEXITED(status)) {
278  ASSERT_EQ(0, WEXITSTATUS(status));
279  return;
280  }
281 
282  // Otherwise the next state must be a system call exit stop. This is
283  // indistinguishable from a system call entry, we just have to keep track
284  // and know that these events happen in pairs.
285  ASSERT_TRUE(WIFSTOPPED(status) && WSTOPSIG(status) == (SIGTRAP | 0x80));
286 
287  if (inject_error) {
288  if (inject_error != -ENOSYS) {
289  ASSERT_EQ(0, ptrace(PTRACE_GETREGS, child_pid, nullptr, &regs));
290  regs.rax = inject_error;
291  ASSERT_EQ(0, ptrace(PTRACE_SETREGS, child_pid, nullptr, &regs));
292  }
293  } else if (is_opening_urandom) {
294  ASSERT_EQ(0, ptrace(PTRACE_GETREGS, child_pid, nullptr, &regs));
295  urandom_fd = regs.rax;
296  } else if (is_urandom_ioctl) {
297  // The result is the number of bits of entropy that the kernel currently
298  // believes that it has. urandom.c waits until 256 bits are ready.
299  int result = 256;
300 
301  // If we are simulating urandom not being ready then we have the ioctl
302  // indicate one too few bits of entropy the first time it's queried.
303  if (flags & URANDOM_NOT_READY) {
304  result--;
305  flags &= ~URANDOM_NOT_READY;
306  }
307 
308  // ptrace always works with ill-defined "words", which appear to be 64-bit
309  // on x86-64. Since the ioctl result is a 32-bit int, do a
310  // read-modify-write to inject the answer.
311  const uintptr_t aligned_addr = ioctl_output_addr & ~7;
312  const uintptr_t offset = ioctl_output_addr - aligned_addr;
313  union {
314  uint64_t word;
315  uint8_t bytes[8];
316  } u;
317  u.word = ptrace(PTRACE_PEEKDATA, child_pid,
318  reinterpret_cast<void *>(aligned_addr), nullptr);
319  memcpy(&u.bytes[offset], &result, sizeof(result));
320  ASSERT_EQ(0, ptrace(PTRACE_POKEDATA, child_pid,
321  reinterpret_cast<void *>(aligned_addr),
322  reinterpret_cast<void *>(u.word)));
323  }
324  }
325 }
326 
327 // TestFunction is the function that |GetTrace| is asked to trace.
328 static void TestFunction() {
329  uint8_t byte;
330  RAND_bytes(&byte, sizeof(byte));
331  RAND_bytes(&byte, sizeof(byte));
332 }
333 
334 static bool have_fork_detection() {
335  return CRYPTO_get_fork_generation() != 0;
336 }
337 
338 // TestFunctionPRNGModel is a model of how the urandom.c code will behave when
339 // |TestFunction| is run. It should return the same trace of events that
340 // |GetTrace| will observe the real code making.
341 static std::vector<Event> TestFunctionPRNGModel(unsigned flags) {
342 #if defined(BORINGSSL_FIPS)
343  static const bool is_fips = true;
344 #else
345  static const bool is_fips = false;
346 #endif
347 
348  std::vector<Event> ret;
349  bool urandom_probed = false;
350  bool getrandom_ready = false;
351 
352  // Probe for getrandom support
353  ret.push_back(Event::GetRandom(1, GRND_NONBLOCK));
355  std::function<bool(bool, size_t)> sysrand;
356 
357  if (flags & NO_GETRANDOM) {
358  ret.push_back(Event::Open("/dev/urandom"));
359  if (flags & NO_URANDOM) {
360  ret.push_back(Event::Abort());
361  return ret;
362  }
363 
364  wait_for_entropy = [&ret, &urandom_probed, flags] {
365  if (!is_fips || urandom_probed) {
366  return;
367  }
368 
369  // Probe urandom for entropy.
370  ret.push_back(Event::UrandomIoctl());
371  if (flags & URANDOM_NOT_READY) {
372  // If the first attempt doesn't report enough entropy, probe
373  // repeatedly until it does, which will happen with the second attempt.
374  ret.push_back(Event::UrandomIoctl());
375  }
376 
377  urandom_probed = true;
378  };
379 
380  sysrand = [&ret, &wait_for_entropy, flags](bool block, size_t len) {
381  if (block) {
383  }
384  ret.push_back(Event::UrandomRead(len));
385  if (flags & URANDOM_ERROR) {
386  ret.push_back(Event::Abort());
387  return false;
388  }
389  return true;
390  };
391  } else {
392  if (flags & GETRANDOM_ERROR) {
393  ret.push_back(Event::Abort());
394  return ret;
395  }
396 
397  getrandom_ready = (flags & GETRANDOM_NOT_READY) == 0;
398  wait_for_entropy = [&ret, &getrandom_ready] {
399  if (getrandom_ready) {
400  return;
401  }
402 
403  ret.push_back(Event::GetRandom(1, GRND_NONBLOCK));
404  ret.push_back(Event::GetRandom(1, 0));
405  getrandom_ready = true;
406  };
407  sysrand = [&ret, &wait_for_entropy](bool block, size_t len) {
408  if (block) {
410  }
411  ret.push_back(Event::GetRandom(len, block ? 0 : GRND_NONBLOCK));
412  return true;
413  };
414  }
415 
416  const size_t kSeedLength = CTR_DRBG_ENTROPY_LEN * (is_fips ? 10 : 1);
417  const size_t kAdditionalDataLength = 32;
418 
419  if (!have_rdrand()) {
420  if ((!have_fork_detection() && !sysrand(true, kAdditionalDataLength)) ||
421  // Initialise CRNGT.
422  (is_fips && !sysrand(true, 16)) ||
423  !sysrand(true, kSeedLength) ||
424  // Second entropy draw.
425  (!have_fork_detection() && !sysrand(true, kAdditionalDataLength))) {
426  return ret;
427  }
428  } else if (
429  // First additional data. If fast RDRAND isn't available then a
430  // non-blocking OS entropy draw will be tried.
431  (!have_fast_rdrand() && !have_fork_detection() &&
432  !sysrand(false, kAdditionalDataLength)) ||
433  // Opportuntistic entropy draw in FIPS mode because RDRAND was used.
434  // In non-FIPS mode it's just drawn from |CRYPTO_sysrand| in a blocking
435  // way.
436  !sysrand(!is_fips, CTR_DRBG_ENTROPY_LEN) ||
437  // Second entropy draw's additional data.
438  (!have_fast_rdrand() && !have_fork_detection() &&
439  !sysrand(false, kAdditionalDataLength))) {
440  return ret;
441  }
442 
443  return ret;
444 }
445 
446 static void CheckInvariants(const std::vector<Event> &events) {
447  // If RDRAND is available then there should be no blocking syscalls in FIPS
448  // mode.
449 #if defined(BORINGSSL_FIPS)
450  if (have_rdrand()) {
451  for (const auto &event : events) {
452  switch (event.type) {
453  case Event::Syscall::kGetRandom:
454  if ((event.flags & GRND_NONBLOCK) == 0) {
455  ADD_FAILURE() << "Blocking getrandom found with RDRAND: "
456  << ToString(events);
457  }
458  break;
459 
460  case Event::Syscall::kUrandomIoctl:
461  ADD_FAILURE() << "Urandom polling found with RDRAND: "
462  << ToString(events);
463  break;
464 
465  default:
466  break;
467  }
468  }
469  }
470 #endif
471 }
472 
473 // Tests that |TestFunctionPRNGModel| is a correct model for the code in
474 // urandom.c, at least to the limits of the the |Event| type.
475 TEST(URandomTest, Test) {
476  char buf[256];
477 
478 #define TRACE_FLAG(flag) \
479  snprintf(buf, sizeof(buf), #flag ": %d", (flags & flag) != 0); \
480  SCOPED_TRACE(buf);
481 
482  for (unsigned flags = 0; flags < NEXT_FLAG; flags++) {
483  TRACE_FLAG(NO_GETRANDOM);
484  TRACE_FLAG(NO_URANDOM);
485  TRACE_FLAG(GETRANDOM_NOT_READY);
486  TRACE_FLAG(URANDOM_NOT_READY);
487  TRACE_FLAG(GETRANDOM_ERROR);
488  TRACE_FLAG(URANDOM_ERROR);
489 
490  const std::vector<Event> expected_trace = TestFunctionPRNGModel(flags);
491  CheckInvariants(expected_trace);
492  std::vector<Event> actual_trace;
493  GetTrace(&actual_trace, flags, TestFunction);
494 
495  if (expected_trace != actual_trace) {
496  ADD_FAILURE() << "Expected: " << ToString(expected_trace)
497  << "\nFound: " << ToString(actual_trace);
498  }
499  }
500 }
501 
502 int main(int argc, char **argv) {
503  ::testing::InitGoogleTest(&argc, argv);
504 
505  if (getenv("BORINGSSL_IGNORE_MADV_WIPEONFORK")) {
507  }
508 
509  return RUN_ALL_TESTS();
510 }
511 
512 #else
513 
514 int main(int argc, char **argv) {
515  printf("PASS\n");
516  return 0;
517 }
518 
519 #endif // X86_64 && !SHARED_LIBRARY && !UNSAFE_DETERMINISTIC_MODE &&
520  // USE_NR_getrandom
wait_for_entropy
static void wait_for_entropy(void)
Definition: urandom.c:228
_gevent_test_main.result
result
Definition: _gevent_test_main.py:96
ASSERT_NE
#define ASSERT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2060
filename
const char * filename
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
RAND_bytes
#define RAND_bytes
Definition: boringssl_prefix_symbols.h:2060
grpc_event_engine::experimental::slice_detail::operator==
bool operator==(const BaseSlice &a, const BaseSlice &b)
Definition: include/grpc/event_engine/slice.h:117
bool
bool
Definition: setup_once.h:312
CRYPTO_get_fork_generation
#define CRYPTO_get_fork_generation
Definition: boringssl_prefix_symbols.h:1166
buf
voidpf void * buf
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
printf
_Use_decl_annotations_ int __cdecl printf(const char *_Format,...)
Definition: cs_driver.c:91
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
u
OPENSSL_EXPORT pem_password_cb void * u
Definition: pem.h:351
status
absl::Status status
Definition: rls.cc:251
Abort
static void Abort(const char *fmt,...)
Definition: acountry.c:94
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
block
Block * block
Definition: protobuf/src/google/protobuf/descriptor.cc:1041
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
absl::FormatConversionChar::e
@ e
ToString
std::string ToString(const grpc::string_ref &r)
Definition: string_ref_helper.cc:24
TEST
#define TEST(name, init_size,...)
Definition: arena_test.cc:75
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
CRYPTO_fork_detect_ignore_madv_wipeonfork_for_testing
OPENSSL_EXPORT void CRYPTO_fork_detect_ignore_madv_wipeonfork_for_testing(void)
syscall
const char * syscall
Definition: third_party/libuv/src/win/internal.h:270
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
RUN_ALL_TESTS
int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2471
have_fast_rdrand
OPENSSL_INLINE int have_fast_rdrand(void)
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:173
ADD_FAILURE
#define ADD_FAILURE()
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1911
TestFunction
static int TestFunction(int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8)
Definition: abi_self_test.cc:24
have_rdrand
OPENSSL_INLINE int have_rdrand(void)
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:169
absl::synchronization_internal::CheckInvariants
static void CheckInvariants(const GraphCycles &gc)
Definition: abseil-cpp/absl/synchronization/internal/graphcycles_test.cc:162
ares::byte
unsigned char byte
Definition: ares-test.h:33
CTR_DRBG_ENTROPY_LEN
#define CTR_DRBG_ENTROPY_LEN
Definition: third_party/boringssl-with-bazel/src/crypto/fipsmodule/rand/internal.h:111
testing::InitGoogleTest
GTEST_API_ void InitGoogleTest(int *argc, char **argv)
Definition: bloaty/third_party/googletest/googletest/src/gtest.cc:6106
rand.h
getrandom_fillin.h
bytes
uint8 bytes[10]
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:153
absl::flags_internal
Definition: abseil-cpp/absl/flags/commandlineflag.h:40
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
main
int main(int argc, char **argv)
Definition: urandom_test.cc:514
fork_detect.h
flags
uint32_t flags
Definition: retry_filter.cc:632
asyncio_get_stats.type
type
Definition: asyncio_get_stats.py:37
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
function
std::function< bool(GrpcTool *, int, const char **, const CliCredentials &, GrpcToolOutputCallback)> function
Definition: grpc_tool.cc:250
length
std::size_t length
Definition: abseil-cpp/absl/time/internal/test_util.cc:57
absl::OnDeadlockCycle::kAbort
@ kAbort
getenv
#define getenv(ptr)
Definition: ares_private.h:106
internal.h
Test
Definition: hpack_parser_test.cc:43
offset
voidpf uLong offset
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:142
ASSERT_EQ
#define ASSERT_EQ(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2056


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:48