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