• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
error_int_name(grpc_error_ints key)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 
error_str_name(grpc_error_strs key)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 
error_time_name(grpc_error_times key)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 
grpc_error_is_special(grpc_error * err)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
grpc_error_ref(grpc_error * err,const char * file,int line)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
grpc_error_ref(grpc_error * err)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 
unref_errs(grpc_error * err)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 
unref_slice(grpc_slice slice)160 static void unref_slice(grpc_slice slice) { grpc_slice_unref_internal(slice); }
161 
unref_strs(grpc_error * err)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 
error_destroy(grpc_error * err)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
grpc_error_unref(grpc_error * err,const char * file,int line)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
grpc_error_unref(grpc_error * err)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 
get_placement(grpc_error ** err,size_t size)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 
internal_set_int(grpc_error ** err,grpc_error_ints which,intptr_t value)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 
internal_set_str(grpc_error ** err,grpc_error_strs which,grpc_slice value)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);
internal_set_time(grpc_error ** err,grpc_error_times which,gpr_timespec value)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 
internal_add_error(grpc_error ** err,grpc_error * new_err)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 
grpc_disable_error_creation()317 void grpc_disable_error_creation() { g_error_creation_allowed = false; }
318 
grpc_enable_error_creation()319 void grpc_enable_error_creation() { g_error_creation_allowed = true; }
320 
grpc_error_create(const char * file,int line,grpc_slice desc,grpc_error ** referencing,size_t num_referencing)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 
ref_strs(grpc_error * err)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 
ref_errs(grpc_error * err)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 
copy_error_and_unref(grpc_error * in)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 
grpc_error_set_int(grpc_error * src,grpc_error_ints which,intptr_t value)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 
grpc_error_get_int(grpc_error * err,grpc_error_ints which,intptr_t * p)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 
grpc_error_set_str(grpc_error * src,grpc_error_strs which,grpc_slice str)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 
grpc_error_get_str(grpc_error * err,grpc_error_strs which,grpc_slice * str)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 
grpc_error_add_child(grpc_error * src,grpc_error * child)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 
append_chr(char c,char ** s,size_t * sz,size_t * cap)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 
append_str(const char * str,char ** s,size_t * sz,size_t * cap)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 
append_esc_str(const uint8_t * str,size_t len,char ** s,size_t * sz,size_t * cap)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 
append_kv(kv_pairs * kvs,char * key,char * value)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 
key_int(grpc_error_ints which)614 static char* key_int(grpc_error_ints which) {
615   return gpr_strdup(error_int_name(which));
616 }
617 
fmt_int(intptr_t p)618 static char* fmt_int(intptr_t p) {
619   char* s;
620   gpr_asprintf(&s, "%" PRIdPTR, p);
621   return s;
622 }
623 
collect_ints_kvs(grpc_error * err,kv_pairs * kvs)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 
key_str(grpc_error_strs which)634 static char* key_str(grpc_error_strs which) {
635   return gpr_strdup(error_str_name(which));
636 }
637 
fmt_str(grpc_slice slice)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 
collect_strs_kvs(grpc_error * err,kv_pairs * kvs)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 
key_time(grpc_error_times which)658 static char* key_time(grpc_error_times which) {
659   return gpr_strdup(error_time_name(which));
660 }
661 
fmt_time(gpr_timespec tm)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 
collect_times_kvs(grpc_error * err,kv_pairs * kvs)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 
add_errs(grpc_error * err,char ** s,size_t * sz,size_t * cap)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 
errs_string(grpc_error * err)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 
cmp_kvs(const void * a,const void * b)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 
finish_kvs(kv_pairs * kvs)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 
grpc_error_string(grpc_error * err)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 
grpc_os_error(const char * file,int line,int err,const char * call_name)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
grpc_wsa_error(const char * file,int line,int err,const char * call_name)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 
grpc_log_if_error(const char * what,grpc_error * error,const char * file,int line)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