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