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