Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / lib / iomgr / error.cc
1 /*
2  *
3  * Copyright 2016 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 #include <grpc/support/port_platform.h>
19
20 #include "src/core/lib/iomgr/error.h"
21
22 #include <inttypes.h>
23 #include <string.h>
24
25 #include <grpc/status.h>
26 #include <grpc/support/alloc.h>
27 #include <grpc/support/log.h>
28 #include <grpc/support/string_util.h>
29
30 #ifdef GPR_WINDOWS
31 #include <grpc/support/log_windows.h>
32 #endif
33
34 #include "src/core/lib/debug/trace.h"
35 #include "src/core/lib/gpr/useful.h"
36 #include "src/core/lib/iomgr/error_internal.h"
37 #include "src/core/lib/profiling/timers.h"
38 #include "src/core/lib/slice/slice_internal.h"
39
40 grpc_core::DebugOnlyTraceFlag grpc_trace_error_refcount(false,
41                                                         "error_refcount");
42 grpc_core::DebugOnlyTraceFlag grpc_trace_closure(false, "closure");
43
44 static const char* error_int_name(grpc_error_ints key) {
45   switch (key) {
46     case GRPC_ERROR_INT_ERRNO:
47       return "errno";
48     case GRPC_ERROR_INT_FILE_LINE:
49       return "file_line";
50     case GRPC_ERROR_INT_STREAM_ID:
51       return "stream_id";
52     case GRPC_ERROR_INT_GRPC_STATUS:
53       return "grpc_status";
54     case GRPC_ERROR_INT_OFFSET:
55       return "offset";
56     case GRPC_ERROR_INT_INDEX:
57       return "index";
58     case GRPC_ERROR_INT_SIZE:
59       return "size";
60     case GRPC_ERROR_INT_HTTP2_ERROR:
61       return "http2_error";
62     case GRPC_ERROR_INT_TSI_CODE:
63       return "tsi_code";
64     case GRPC_ERROR_INT_SECURITY_STATUS:
65       return "security_status";
66     case GRPC_ERROR_INT_FD:
67       return "fd";
68     case GRPC_ERROR_INT_WSA_ERROR:
69       return "wsa_error";
70     case GRPC_ERROR_INT_HTTP_STATUS:
71       return "http_status";
72     case GRPC_ERROR_INT_LIMIT:
73       return "limit";
74     case GRPC_ERROR_INT_OCCURRED_DURING_WRITE:
75       return "occurred_during_write";
76     case GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE:
77       return "channel_connectivity_state";
78     case GRPC_ERROR_INT_MAX:
79       GPR_UNREACHABLE_CODE(return "unknown");
80   }
81   GPR_UNREACHABLE_CODE(return "unknown");
82 }
83
84 static const char* error_str_name(grpc_error_strs key) {
85   switch (key) {
86     case GRPC_ERROR_STR_KEY:
87       return "key";
88     case GRPC_ERROR_STR_VALUE:
89       return "value";
90     case GRPC_ERROR_STR_DESCRIPTION:
91       return "description";
92     case GRPC_ERROR_STR_OS_ERROR:
93       return "os_error";
94     case GRPC_ERROR_STR_TARGET_ADDRESS:
95       return "target_address";
96     case GRPC_ERROR_STR_SYSCALL:
97       return "syscall";
98     case GRPC_ERROR_STR_FILE:
99       return "file";
100     case GRPC_ERROR_STR_GRPC_MESSAGE:
101       return "grpc_message";
102     case GRPC_ERROR_STR_RAW_BYTES:
103       return "raw_bytes";
104     case GRPC_ERROR_STR_TSI_ERROR:
105       return "tsi_error";
106     case GRPC_ERROR_STR_FILENAME:
107       return "filename";
108     case GRPC_ERROR_STR_QUEUED_BUFFERS:
109       return "queued_buffers";
110     case GRPC_ERROR_STR_MAX:
111       GPR_UNREACHABLE_CODE(return "unknown");
112   }
113   GPR_UNREACHABLE_CODE(return "unknown");
114 }
115
116 static const char* error_time_name(grpc_error_times key) {
117   switch (key) {
118     case GRPC_ERROR_TIME_CREATED:
119       return "created";
120     case GRPC_ERROR_TIME_MAX:
121       GPR_UNREACHABLE_CODE(return "unknown");
122   }
123   GPR_UNREACHABLE_CODE(return "unknown");
124 }
125
126 #ifndef NDEBUG
127 grpc_error* grpc_error_do_ref(grpc_error* err, const char* file, int line) {
128   if (grpc_trace_error_refcount.enabled()) {
129     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
130             gpr_atm_no_barrier_load(&err->atomics.refs.count),
131             gpr_atm_no_barrier_load(&err->atomics.refs.count) + 1, file, line);
132   }
133   gpr_ref(&err->atomics.refs);
134   return err;
135 }
136 #else
137 grpc_error* grpc_error_do_ref(grpc_error* err) {
138   gpr_ref(&err->atomics.refs);
139   return err;
140 }
141 #endif
142
143 static void unref_errs(grpc_error* err) {
144   uint8_t slot = err->first_err;
145   while (slot != UINT8_MAX) {
146     grpc_linked_error* lerr =
147         reinterpret_cast<grpc_linked_error*>(err->arena + slot);
148     GRPC_ERROR_UNREF(lerr->err);
149     GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
150                                      : lerr->next != UINT8_MAX);
151     slot = lerr->next;
152   }
153 }
154
155 static void unref_strs(grpc_error* err) {
156   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
157     uint8_t slot = err->strs[which];
158     if (slot != UINT8_MAX) {
159       grpc_slice_unref_internal(
160           *reinterpret_cast<grpc_slice*>(err->arena + slot));
161     }
162   }
163 }
164
165 static void error_destroy(grpc_error* err) {
166   GPR_ASSERT(!grpc_error_is_special(err));
167   unref_errs(err);
168   unref_strs(err);
169   gpr_free((void*)gpr_atm_acq_load(&err->atomics.error_string));
170   gpr_free(err);
171 }
172
173 #ifndef NDEBUG
174 void grpc_error_do_unref(grpc_error* err, const char* file, int line) {
175   if (grpc_trace_error_refcount.enabled()) {
176     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
177             gpr_atm_no_barrier_load(&err->atomics.refs.count),
178             gpr_atm_no_barrier_load(&err->atomics.refs.count) - 1, file, line);
179   }
180   if (gpr_unref(&err->atomics.refs)) {
181     error_destroy(err);
182   }
183 }
184 #else
185 void grpc_error_do_unref(grpc_error* err) {
186   if (gpr_unref(&err->atomics.refs)) {
187     error_destroy(err);
188   }
189 }
190 #endif
191
192 static uint8_t get_placement(grpc_error** err, size_t size) {
193   GPR_ASSERT(*err);
194   uint8_t slots = static_cast<uint8_t>(size / sizeof(intptr_t));
195   if ((*err)->arena_size + slots > (*err)->arena_capacity) {
196     (*err)->arena_capacity = static_cast<uint8_t> GPR_MIN(
197         UINT8_MAX - 1, (3 * (*err)->arena_capacity / 2));
198     if ((*err)->arena_size + slots > (*err)->arena_capacity) {
199       return UINT8_MAX;
200     }
201 #ifndef NDEBUG
202     grpc_error* orig = *err;
203 #endif
204     *err = static_cast<grpc_error*>(gpr_realloc(
205         *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t)));
206 #ifndef NDEBUG
207     if (grpc_trace_error_refcount.enabled()) {
208       if (*err != orig) {
209         gpr_log(GPR_DEBUG, "realloc %p -> %p", orig, *err);
210       }
211     }
212 #endif
213   }
214   uint8_t placement = (*err)->arena_size;
215   (*err)->arena_size = static_cast<uint8_t>((*err)->arena_size + slots);
216   return placement;
217 }
218
219 static void internal_set_int(grpc_error** err, grpc_error_ints which,
220                              intptr_t value) {
221   uint8_t slot = (*err)->ints[which];
222   if (slot == UINT8_MAX) {
223     slot = get_placement(err, sizeof(value));
224     if (slot == UINT8_MAX) {
225       gpr_log(GPR_ERROR, "Error %p is full, dropping int {\"%s\":%" PRIiPTR "}",
226               *err, error_int_name(which), value);
227       return;
228     }
229   }
230   (*err)->ints[which] = slot;
231   (*err)->arena[slot] = value;
232 }
233
234 static void internal_set_str(grpc_error** err, grpc_error_strs which,
235                              const grpc_slice& value) {
236   uint8_t slot = (*err)->strs[which];
237   if (slot == UINT8_MAX) {
238     slot = get_placement(err, sizeof(value));
239     if (slot == UINT8_MAX) {
240       const char* str = grpc_slice_to_c_string(value);
241       gpr_log(GPR_ERROR, "Error %p is full, dropping string {\"%s\":\"%s\"}",
242               *err, error_str_name(which), str);
243       gpr_free((void*)str);
244       return;
245     }
246   } else {
247     grpc_slice_unref_internal(
248         *reinterpret_cast<grpc_slice*>((*err)->arena + slot));
249   }
250   (*err)->strs[which] = slot;
251   memcpy((*err)->arena + slot, &value, sizeof(value));
252 }
253
254 static char* fmt_time(gpr_timespec tm);
255 static void internal_set_time(grpc_error** err, grpc_error_times which,
256                               gpr_timespec value) {
257   uint8_t slot = (*err)->times[which];
258   if (slot == UINT8_MAX) {
259     slot = get_placement(err, sizeof(value));
260     if (slot == UINT8_MAX) {
261       const char* time_str = fmt_time(value);
262       gpr_log(GPR_ERROR, "Error %p is full, dropping \"%s\":\"%s\"}", *err,
263               error_time_name(which), time_str);
264       gpr_free((void*)time_str);
265       return;
266     }
267   }
268   (*err)->times[which] = slot;
269   memcpy((*err)->arena + slot, &value, sizeof(value));
270 }
271
272 static void internal_add_error(grpc_error** err, grpc_error* new_err) {
273   grpc_linked_error new_last = {new_err, UINT8_MAX};
274   uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
275   if (slot == UINT8_MAX) {
276     gpr_log(GPR_ERROR, "Error %p is full, dropping error %p = %s", *err,
277             new_err, grpc_error_string(new_err));
278     GRPC_ERROR_UNREF(new_err);
279     return;
280   }
281   if ((*err)->first_err == UINT8_MAX) {
282     GPR_ASSERT((*err)->last_err == UINT8_MAX);
283     (*err)->last_err = slot;
284     (*err)->first_err = slot;
285   } else {
286     GPR_ASSERT((*err)->last_err != UINT8_MAX);
287     grpc_linked_error* old_last =
288         reinterpret_cast<grpc_linked_error*>((*err)->arena + (*err)->last_err);
289     old_last->next = slot;
290     (*err)->last_err = slot;
291   }
292   memcpy((*err)->arena + slot, &new_last, sizeof(grpc_linked_error));
293 }
294
295 #define SLOTS_PER_INT (sizeof(intptr_t) / sizeof(intptr_t))
296 #define SLOTS_PER_STR (sizeof(grpc_slice) / sizeof(intptr_t))
297 #define SLOTS_PER_TIME (sizeof(gpr_timespec) / sizeof(intptr_t))
298 #define SLOTS_PER_LINKED_ERROR (sizeof(grpc_linked_error) / sizeof(intptr_t))
299
300 // size of storing one int and two slices and a timespec. For line, desc, file,
301 // and time created
302 #define DEFAULT_ERROR_CAPACITY \
303   (SLOTS_PER_INT + (SLOTS_PER_STR * 2) + SLOTS_PER_TIME)
304
305 // It is very common to include and extra int and string in an error
306 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
307
308 static gpr_atm g_error_creation_allowed = true;
309
310 void grpc_disable_error_creation() {
311   gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
312 }
313
314 void grpc_enable_error_creation() {
315   gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
316 }
317
318 grpc_error* grpc_error_create(const char* file, int line,
319                               const grpc_slice& desc, grpc_error** referencing,
320                               size_t num_referencing) {
321   GPR_TIMER_SCOPE("grpc_error_create", 0);
322   uint8_t initial_arena_capacity = static_cast<uint8_t>(
323       DEFAULT_ERROR_CAPACITY +
324       static_cast<uint8_t>(num_referencing * SLOTS_PER_LINKED_ERROR) +
325       SURPLUS_CAPACITY);
326   grpc_error* err = static_cast<grpc_error*>(
327       gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t)));
328   if (err == nullptr) {  // TODO(ctiller): make gpr_malloc return NULL
329     return GRPC_ERROR_OOM;
330   }
331 #ifndef NDEBUG
332   if (!gpr_atm_no_barrier_load(&g_error_creation_allowed)) {
333     gpr_log(GPR_ERROR,
334             "Error creation occurred when error creation was disabled [%s:%d]",
335             file, line);
336     abort();
337   }
338   if (grpc_trace_error_refcount.enabled()) {
339     gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
340   }
341 #endif
342
343   err->arena_size = 0;
344   err->arena_capacity = initial_arena_capacity;
345   err->first_err = UINT8_MAX;
346   err->last_err = UINT8_MAX;
347
348   memset(err->ints, UINT8_MAX, GRPC_ERROR_INT_MAX);
349   memset(err->strs, UINT8_MAX, GRPC_ERROR_STR_MAX);
350   memset(err->times, UINT8_MAX, GRPC_ERROR_TIME_MAX);
351
352   internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line);
353   internal_set_str(&err, GRPC_ERROR_STR_FILE,
354                    grpc_slice_from_static_string(file));
355   internal_set_str(&err, GRPC_ERROR_STR_DESCRIPTION, desc);
356
357   for (size_t i = 0; i < num_referencing; ++i) {
358     if (referencing[i] == GRPC_ERROR_NONE) continue;
359     internal_add_error(
360         &err,
361         GRPC_ERROR_REF(
362             referencing[i]));  // TODO(ncteisen), change ownership semantics
363   }
364
365   internal_set_time(&err, GRPC_ERROR_TIME_CREATED, gpr_now(GPR_CLOCK_REALTIME));
366
367   gpr_atm_no_barrier_store(&err->atomics.error_string, 0);
368   gpr_ref_init(&err->atomics.refs, 1);
369   return err;
370 }
371
372 static void ref_strs(grpc_error* err) {
373   for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) {
374     uint8_t slot = err->strs[i];
375     if (slot != UINT8_MAX) {
376       grpc_slice_ref_internal(
377           *reinterpret_cast<grpc_slice*>(err->arena + slot));
378     }
379   }
380 }
381
382 static void ref_errs(grpc_error* err) {
383   uint8_t slot = err->first_err;
384   while (slot != UINT8_MAX) {
385     grpc_linked_error* lerr =
386         reinterpret_cast<grpc_linked_error*>(err->arena + slot);
387     GRPC_ERROR_REF(lerr->err);
388     slot = lerr->next;
389   }
390 }
391
392 static grpc_error* copy_error_and_unref(grpc_error* in) {
393   GPR_TIMER_SCOPE("copy_error_and_unref", 0);
394   grpc_error* out;
395   if (grpc_error_is_special(in)) {
396     out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown");
397     if (in == GRPC_ERROR_NONE) {
398       internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
399                        grpc_slice_from_static_string("no error"));
400       internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK);
401     } else if (in == GRPC_ERROR_OOM) {
402       internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
403                        grpc_slice_from_static_string("oom"));
404     } else if (in == GRPC_ERROR_CANCELLED) {
405       internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
406                        grpc_slice_from_static_string("cancelled"));
407       internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED);
408     }
409   } else if (gpr_ref_is_unique(&in->atomics.refs)) {
410     out = in;
411   } else {
412     uint8_t new_arena_capacity = in->arena_capacity;
413     // the returned err will be added to, so we ensure this is room to avoid
414     // unneeded allocations.
415     if (in->arena_capacity - in->arena_size <
416         static_cast<uint8_t> SLOTS_PER_STR) {
417       new_arena_capacity = static_cast<uint8_t>(3 * new_arena_capacity / 2);
418     }
419     out = static_cast<grpc_error*>(
420         gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t)));
421 #ifndef NDEBUG
422     if (grpc_trace_error_refcount.enabled()) {
423       gpr_log(GPR_DEBUG, "%p create copying %p", out, in);
424     }
425 #endif
426     // bulk memcpy of the rest of the struct.
427     size_t skip = sizeof(&out->atomics);
428     memcpy((void*)((uintptr_t)out + skip), (void*)((uintptr_t)in + skip),
429            sizeof(*in) + (in->arena_size * sizeof(intptr_t)) - skip);
430     // manually set the atomics and the new capacity
431     gpr_atm_no_barrier_store(&out->atomics.error_string, 0);
432     gpr_ref_init(&out->atomics.refs, 1);
433     out->arena_capacity = new_arena_capacity;
434     ref_strs(out);
435     ref_errs(out);
436     GRPC_ERROR_UNREF(in);
437   }
438   return out;
439 }
440
441 grpc_error* grpc_error_set_int(grpc_error* src, grpc_error_ints which,
442                                intptr_t value) {
443   GPR_TIMER_SCOPE("grpc_error_set_int", 0);
444   grpc_error* new_err = copy_error_and_unref(src);
445   internal_set_int(&new_err, which, value);
446   return new_err;
447 }
448
449 typedef struct {
450   grpc_status_code code;
451   const char* msg;
452   size_t len;
453 } special_error_status_map;
454
455 const special_error_status_map error_status_map[] = {
456     {GRPC_STATUS_OK, "", 0},                // GRPC_ERROR_NONE
457     {GRPC_STATUS_INVALID_ARGUMENT, "", 0},  // GRPC_ERROR_RESERVED_1
458     {GRPC_STATUS_RESOURCE_EXHAUSTED, "Out of memory",
459      strlen("Out of memory")},              // GRPC_ERROR_OOM
460     {GRPC_STATUS_INVALID_ARGUMENT, "", 0},  // GRPC_ERROR_RESERVED_2
461     {GRPC_STATUS_CANCELLED, "Cancelled",
462      strlen("Cancelled")},  // GRPC_ERROR_CANCELLED
463 };
464
465 bool grpc_error_get_int(grpc_error* err, grpc_error_ints which, intptr_t* p) {
466   GPR_TIMER_SCOPE("grpc_error_get_int", 0);
467   if (grpc_error_is_special(err)) {
468     if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
469     *p = error_status_map[reinterpret_cast<size_t>(err)].code;
470     return true;
471   }
472   uint8_t slot = err->ints[which];
473   if (slot != UINT8_MAX) {
474     if (p != nullptr) *p = err->arena[slot];
475     return true;
476   }
477   return false;
478 }
479
480 grpc_error* grpc_error_set_str(grpc_error* src, grpc_error_strs which,
481                                const grpc_slice& str) {
482   GPR_TIMER_SCOPE("grpc_error_set_str", 0);
483   grpc_error* new_err = copy_error_and_unref(src);
484   internal_set_str(&new_err, which, str);
485   return new_err;
486 }
487
488 bool grpc_error_get_str(grpc_error* err, grpc_error_strs which,
489                         grpc_slice* str) {
490   if (grpc_error_is_special(err)) {
491     if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
492     const special_error_status_map& msg =
493         error_status_map[reinterpret_cast<size_t>(err)];
494     str->refcount = &grpc_core::kNoopRefcount;
495     str->data.refcounted.bytes =
496         reinterpret_cast<uint8_t*>(const_cast<char*>(msg.msg));
497     str->data.refcounted.length = msg.len;
498     return true;
499   }
500   uint8_t slot = err->strs[which];
501   if (slot != UINT8_MAX) {
502     *str = *reinterpret_cast<grpc_slice*>(err->arena + slot);
503     return true;
504   } else {
505     return false;
506   }
507 }
508
509 grpc_error* grpc_error_add_child(grpc_error* src, grpc_error* child) {
510   GPR_TIMER_SCOPE("grpc_error_add_child", 0);
511   if (src != GRPC_ERROR_NONE) {
512     if (child == GRPC_ERROR_NONE) {
513       /* \a child is empty. Simply return the ref to \a src */
514       return src;
515     } else if (child != src) {
516       grpc_error* new_err = copy_error_and_unref(src);
517       internal_add_error(&new_err, child);
518       return new_err;
519     } else {
520       /* \a src and \a child are the same. Drop one of the references and return
521        * the other */
522       GRPC_ERROR_UNREF(child);
523       return src;
524     }
525   } else {
526     /* \a src is empty. Simply return the ref to \a child */
527     return child;
528   }
529 }
530
531 static const char* no_error_string = "\"No Error\"";
532 static const char* oom_error_string = "\"Out of memory\"";
533 static const char* cancelled_error_string = "\"Cancelled\"";
534
535 typedef struct {
536   char* key;
537   char* value;
538 } kv_pair;
539
540 typedef struct {
541   kv_pair* kvs;
542   size_t num_kvs;
543   size_t cap_kvs;
544 } kv_pairs;
545
546 static void append_chr(char c, char** s, size_t* sz, size_t* cap) {
547   if (*sz == *cap) {
548     *cap = GPR_MAX(8, 3 * *cap / 2);
549     *s = static_cast<char*>(gpr_realloc(*s, *cap));
550   }
551   (*s)[(*sz)++] = c;
552 }
553
554 static void append_str(const char* str, char** s, size_t* sz, size_t* cap) {
555   for (const char* c = str; *c; c++) {
556     append_chr(*c, s, sz, cap);
557   }
558 }
559
560 static void append_esc_str(const uint8_t* str, size_t len, char** s, size_t* sz,
561                            size_t* cap) {
562   static const char* hex = "0123456789abcdef";
563   append_chr('"', s, sz, cap);
564   for (size_t i = 0; i < len; i++, str++) {
565     if (*str < 32 || *str >= 127) {
566       append_chr('\\', s, sz, cap);
567       switch (*str) {
568         case '\b':
569           append_chr('b', s, sz, cap);
570           break;
571         case '\f':
572           append_chr('f', s, sz, cap);
573           break;
574         case '\n':
575           append_chr('n', s, sz, cap);
576           break;
577         case '\r':
578           append_chr('r', s, sz, cap);
579           break;
580         case '\t':
581           append_chr('t', s, sz, cap);
582           break;
583         default:
584           append_chr('u', s, sz, cap);
585           append_chr('0', s, sz, cap);
586           append_chr('0', s, sz, cap);
587           append_chr(hex[*str >> 4], s, sz, cap);
588           append_chr(hex[*str & 0x0f], s, sz, cap);
589           break;
590       }
591     } else {
592       append_chr(static_cast<char>(*str), s, sz, cap);
593     }
594   }
595   append_chr('"', s, sz, cap);
596 }
597
598 static void append_kv(kv_pairs* kvs, char* key, char* value) {
599   if (kvs->num_kvs == kvs->cap_kvs) {
600     kvs->cap_kvs = GPR_MAX(3 * kvs->cap_kvs / 2, 4);
601     kvs->kvs = static_cast<kv_pair*>(
602         gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs));
603   }
604   kvs->kvs[kvs->num_kvs].key = key;
605   kvs->kvs[kvs->num_kvs].value = value;
606   kvs->num_kvs++;
607 }
608
609 static char* key_int(grpc_error_ints which) {
610   return gpr_strdup(error_int_name(which));
611 }
612
613 static char* fmt_int(intptr_t p) {
614   char* s;
615   gpr_asprintf(&s, "%" PRIdPTR, p);
616   return s;
617 }
618
619 static void collect_ints_kvs(grpc_error* err, kv_pairs* kvs) {
620   for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) {
621     uint8_t slot = err->ints[which];
622     if (slot != UINT8_MAX) {
623       append_kv(kvs, key_int(static_cast<grpc_error_ints>(which)),
624                 fmt_int(err->arena[slot]));
625     }
626   }
627 }
628
629 static char* key_str(grpc_error_strs which) {
630   return gpr_strdup(error_str_name(which));
631 }
632
633 static char* fmt_str(const grpc_slice& slice) {
634   char* s = nullptr;
635   size_t sz = 0;
636   size_t cap = 0;
637   append_esc_str((const uint8_t*)GRPC_SLICE_START_PTR(slice),
638                  GRPC_SLICE_LENGTH(slice), &s, &sz, &cap);
639   append_chr(0, &s, &sz, &cap);
640   return s;
641 }
642
643 static void collect_strs_kvs(grpc_error* err, kv_pairs* kvs) {
644   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
645     uint8_t slot = err->strs[which];
646     if (slot != UINT8_MAX) {
647       append_kv(kvs, key_str(static_cast<grpc_error_strs>(which)),
648                 fmt_str(*reinterpret_cast<grpc_slice*>(err->arena + slot)));
649     }
650   }
651 }
652
653 static char* key_time(grpc_error_times which) {
654   return gpr_strdup(error_time_name(which));
655 }
656
657 static char* fmt_time(gpr_timespec tm) {
658   char* out;
659   const char* pfx = "!!";
660   switch (tm.clock_type) {
661     case GPR_CLOCK_MONOTONIC:
662       pfx = "@monotonic:";
663       break;
664     case GPR_CLOCK_REALTIME:
665       pfx = "@";
666       break;
667     case GPR_CLOCK_PRECISE:
668       pfx = "@precise:";
669       break;
670     case GPR_TIMESPAN:
671       pfx = "";
672       break;
673   }
674   gpr_asprintf(&out, "\"%s%" PRId64 ".%09d\"", pfx, tm.tv_sec, tm.tv_nsec);
675   return out;
676 }
677
678 static void collect_times_kvs(grpc_error* err, kv_pairs* kvs) {
679   for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) {
680     uint8_t slot = err->times[which];
681     if (slot != UINT8_MAX) {
682       append_kv(kvs, key_time(static_cast<grpc_error_times>(which)),
683                 fmt_time(*reinterpret_cast<gpr_timespec*>(err->arena + slot)));
684     }
685   }
686 }
687
688 static void add_errs(grpc_error* err, char** s, size_t* sz, size_t* cap) {
689   uint8_t slot = err->first_err;
690   bool first = true;
691   while (slot != UINT8_MAX) {
692     grpc_linked_error* lerr =
693         reinterpret_cast<grpc_linked_error*>(err->arena + slot);
694     if (!first) append_chr(',', s, sz, cap);
695     first = false;
696     const char* e = grpc_error_string(lerr->err);
697     append_str(e, s, sz, cap);
698     GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
699                                      : lerr->next != UINT8_MAX);
700     slot = lerr->next;
701   }
702 }
703
704 static char* errs_string(grpc_error* err) {
705   char* s = nullptr;
706   size_t sz = 0;
707   size_t cap = 0;
708   append_chr('[', &s, &sz, &cap);
709   add_errs(err, &s, &sz, &cap);
710   append_chr(']', &s, &sz, &cap);
711   append_chr(0, &s, &sz, &cap);
712   return s;
713 }
714
715 static int cmp_kvs(const void* a, const void* b) {
716   const kv_pair* ka = static_cast<const kv_pair*>(a);
717   const kv_pair* kb = static_cast<const kv_pair*>(b);
718   return strcmp(ka->key, kb->key);
719 }
720
721 static char* finish_kvs(kv_pairs* kvs) {
722   char* s = nullptr;
723   size_t sz = 0;
724   size_t cap = 0;
725
726   append_chr('{', &s, &sz, &cap);
727   for (size_t i = 0; i < kvs->num_kvs; i++) {
728     if (i != 0) append_chr(',', &s, &sz, &cap);
729     append_esc_str(reinterpret_cast<const uint8_t*>(kvs->kvs[i].key),
730                    strlen(kvs->kvs[i].key), &s, &sz, &cap);
731     gpr_free(kvs->kvs[i].key);
732     append_chr(':', &s, &sz, &cap);
733     append_str(kvs->kvs[i].value, &s, &sz, &cap);
734     gpr_free(kvs->kvs[i].value);
735   }
736   append_chr('}', &s, &sz, &cap);
737   append_chr(0, &s, &sz, &cap);
738
739   gpr_free(kvs->kvs);
740   return s;
741 }
742
743 const char* grpc_error_string(grpc_error* err) {
744   GPR_TIMER_SCOPE("grpc_error_string", 0);
745   if (err == GRPC_ERROR_NONE) return no_error_string;
746   if (err == GRPC_ERROR_OOM) return oom_error_string;
747   if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string;
748
749   void* p = (void*)gpr_atm_acq_load(&err->atomics.error_string);
750   if (p != nullptr) {
751     return static_cast<const char*>(p);
752   }
753
754   kv_pairs kvs;
755   memset(&kvs, 0, sizeof(kvs));
756
757   collect_ints_kvs(err, &kvs);
758   collect_strs_kvs(err, &kvs);
759   collect_times_kvs(err, &kvs);
760   if (err->first_err != UINT8_MAX) {
761     append_kv(&kvs, gpr_strdup("referenced_errors"), errs_string(err));
762   }
763
764   qsort(kvs.kvs, kvs.num_kvs, sizeof(kv_pair), cmp_kvs);
765
766   char* out = finish_kvs(&kvs);
767
768   if (!gpr_atm_rel_cas(&err->atomics.error_string, 0, (gpr_atm)out)) {
769     gpr_free(out);
770     out = (char*)gpr_atm_acq_load(&err->atomics.error_string);
771   }
772
773   return out;
774 }
775
776 grpc_error* grpc_os_error(const char* file, int line, int err,
777                           const char* call_name) {
778   return grpc_error_set_str(
779       grpc_error_set_str(
780           grpc_error_set_int(
781               grpc_error_create(file, line,
782                                 grpc_slice_from_static_string(strerror(err)),
783                                 nullptr, 0),
784               GRPC_ERROR_INT_ERRNO, err),
785           GRPC_ERROR_STR_OS_ERROR,
786           grpc_slice_from_static_string(strerror(err))),
787       GRPC_ERROR_STR_SYSCALL, grpc_slice_from_copied_string(call_name));
788 }
789
790 #ifdef GPR_WINDOWS
791 grpc_error* grpc_wsa_error(const char* file, int line, int err,
792                            const char* call_name) {
793   char* utf8_message = gpr_format_message(err);
794   grpc_error* error = grpc_error_set_str(
795       grpc_error_set_str(
796           grpc_error_set_int(
797               grpc_error_create(file, line,
798                                 grpc_slice_from_static_string("OS Error"), NULL,
799                                 0),
800               GRPC_ERROR_INT_WSA_ERROR, err),
801           GRPC_ERROR_STR_OS_ERROR, grpc_slice_from_copied_string(utf8_message)),
802       GRPC_ERROR_STR_SYSCALL, grpc_slice_from_static_string(call_name));
803   gpr_free(utf8_message);
804   return error;
805 }
806 #endif
807
808 bool grpc_log_error(const char* what, grpc_error* error, const char* file,
809                     int line) {
810   GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
811   const char* msg = grpc_error_string(error);
812   gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
813   GRPC_ERROR_UNREF(error);
814   return false;
815 }