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/impl/codegen/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/slice/slice_internal.h"
38 #include "src/core/lib/slice/slice_utils.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 gpr_atm g_error_creation_allowed = true;
45 
grpc_disable_error_creation()46 void grpc_disable_error_creation() {
47   gpr_atm_no_barrier_store(&g_error_creation_allowed, false);
48 }
49 
grpc_enable_error_creation()50 void grpc_enable_error_creation() {
51   gpr_atm_no_barrier_store(&g_error_creation_allowed, true);
52 }
53 
54 #ifdef GRPC_ERROR_IS_ABSEIL_STATUS
55 
grpc_status_create(absl::StatusCode code,absl::string_view msg,const grpc_core::DebugLocation & location,size_t children_count,absl::Status * children)56 absl::Status grpc_status_create(absl::StatusCode code, absl::string_view msg,
57                                 const grpc_core::DebugLocation& location,
58                                 size_t children_count, absl::Status* children) {
59   absl::Status s = StatusCreate(code, msg, location, {});
60   for (size_t i = 0; i < children_count; ++i) {
61     if (!children[i].ok()) {
62       grpc_core::StatusAddChild(&s, children[i]);
63     }
64   }
65   return s;
66 }
67 
grpc_error_std_string(absl::Status error)68 std::string grpc_error_std_string(absl::Status error) {
69   return grpc_core::StatusToString(error);
70 }
71 
grpc_os_error(const grpc_core::DebugLocation & location,int err,const char * call_name)72 absl::Status grpc_os_error(const grpc_core::DebugLocation& location, int err,
73                            const char* call_name) {
74   absl::Status s =
75       StatusCreate(absl::StatusCode::kUnknown, "OS Error", location, {});
76   grpc_core::StatusSetInt(&s, grpc_core::StatusIntProperty::kErrorNo, err);
77   grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::kOsError,
78                           strerror(err));
79   grpc_core::StatusSetStr(&s, grpc_core::StatusStrProperty::kSyscall,
80                           call_name);
81   return s;
82 }
83 
84 #ifdef GPR_WINDOWS
grpc_wsa_error(const grpc_core::DebugLocation & location,int err,const char * call_name)85 absl::Status grpc_wsa_error(const grpc_core::DebugLocation& location, int err,
86                             const char* call_name) {
87   char* utf8_message = gpr_format_message(err);
88   absl::Status s =
89       StatusCreate(absl::StatusCode::kUnknown, "WSA Error", location, {});
90   StatusSetInt(&s, grpc_core::StatusIntProperty::kWsaError, err);
91   StatusSetStr(&s, grpc_core::StatusStrProperty::kOsError, utf8_message);
92   StatusSetStr(&s, grpc_core::StatusStrProperty::kSyscall, call_name);
93   return s;
94 }
95 #endif
96 
grpc_error_set_int(grpc_error_handle src,grpc_error_ints which,intptr_t value)97 grpc_error_handle grpc_error_set_int(grpc_error_handle src,
98                                      grpc_error_ints which, intptr_t value) {
99   if (src == GRPC_ERROR_NONE) {
100     src = absl::UnknownError("");
101     StatusSetInt(&src, grpc_core::StatusIntProperty::kRpcStatus,
102                  GRPC_STATUS_OK);
103   }
104   grpc_core::StatusSetInt(
105       &src, static_cast<grpc_core::StatusIntProperty>(which), value);
106   return src;
107 }
108 
grpc_error_get_int(grpc_error_handle error,grpc_error_ints which,intptr_t * p)109 bool grpc_error_get_int(grpc_error_handle error, grpc_error_ints which,
110                         intptr_t* p) {
111   absl::optional<intptr_t> value = grpc_core::StatusGetInt(
112       error, static_cast<grpc_core::StatusIntProperty>(which));
113   if (value.has_value()) {
114     *p = *value;
115     return true;
116   } else {
117     // TODO(veblush): Remove this once absl::Status migration is done
118     if (which == GRPC_ERROR_INT_GRPC_STATUS) {
119       switch (error.code()) {
120         case absl::StatusCode::kOk:
121           *p = GRPC_STATUS_OK;
122           return true;
123         case absl::StatusCode::kResourceExhausted:
124           *p = GRPC_STATUS_RESOURCE_EXHAUSTED;
125           return true;
126         case absl::StatusCode::kCancelled:
127           *p = GRPC_STATUS_CANCELLED;
128           return true;
129         default:
130           break;
131       }
132     }
133     return false;
134   }
135 }
136 
grpc_error_set_str(grpc_error_handle src,grpc_error_strs which,absl::string_view str)137 grpc_error_handle grpc_error_set_str(grpc_error_handle src,
138                                      grpc_error_strs which,
139                                      absl::string_view str) {
140   if (src == GRPC_ERROR_NONE) {
141     src = absl::UnknownError("");
142     StatusSetInt(&src, grpc_core::StatusIntProperty::kRpcStatus,
143                  GRPC_STATUS_OK);
144   }
145   if (which == GRPC_ERROR_STR_DESCRIPTION) {
146     // To change the message of absl::Status, a new instance should be created
147     // with a code and payload because it doesn't have a setter for it.
148     absl::Status s = absl::Status(src.code(), str);
149     src.ForEachPayload(
150         [&](absl::string_view type_url, const absl::Cord& payload) {
151           s.SetPayload(type_url, payload);
152         });
153     return s;
154   } else {
155     grpc_core::StatusSetStr(
156         &src, static_cast<grpc_core::StatusStrProperty>(which), str);
157   }
158   return src;
159 }
160 
grpc_error_get_str(grpc_error_handle error,grpc_error_strs which,std::string * s)161 bool grpc_error_get_str(grpc_error_handle error, grpc_error_strs which,
162                         std::string* s) {
163   if (which == GRPC_ERROR_STR_DESCRIPTION) {
164     // absl::Status uses the message field for GRPC_ERROR_STR_DESCRIPTION
165     // instead of using payload.
166     absl::string_view msg = error.message();
167     if (msg.empty()) {
168       return false;
169     } else {
170       *s = std::string(msg);
171       return true;
172     }
173   } else {
174     absl::optional<std::string> value = grpc_core::StatusGetStr(
175         error, static_cast<grpc_core::StatusStrProperty>(which));
176     if (value.has_value()) {
177       *s = std::move(*value);
178       return true;
179     } else {
180       // TODO(veblush): Remove this once absl::Status migration is done
181       if (which == GRPC_ERROR_STR_GRPC_MESSAGE) {
182         switch (error.code()) {
183           case absl::StatusCode::kOk:
184             *s = "";
185             return true;
186           case absl::StatusCode::kResourceExhausted:
187             *s = "RESOURCE_EXHAUSTED";
188             return true;
189           case absl::StatusCode::kCancelled:
190             *s = "CANCELLED";
191             return true;
192           default:
193             break;
194         }
195       }
196       return false;
197     }
198   }
199 }
200 
grpc_error_add_child(grpc_error_handle src,grpc_error_handle child)201 grpc_error_handle grpc_error_add_child(grpc_error_handle src,
202                                        grpc_error_handle child) {
203   if (src.ok()) {
204     return child;
205   } else {
206     if (!child.ok()) {
207       grpc_core::StatusAddChild(&src, child);
208     }
209     return src;
210   }
211 }
212 
grpc_log_error(const char * what,grpc_error_handle error,const char * file,int line)213 bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
214                     int line) {
215   GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
216   gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what,
217           grpc_core::StatusToString(error).c_str());
218   return false;
219 }
220 
221 #else  // GRPC_ERROR_IS_ABSEIL_STATUS
222 
error_int_name(grpc_error_ints key)223 static const char* error_int_name(grpc_error_ints key) {
224   switch (key) {
225     case GRPC_ERROR_INT_ERRNO:
226       return "errno";
227     case GRPC_ERROR_INT_FILE_LINE:
228       return "file_line";
229     case GRPC_ERROR_INT_STREAM_ID:
230       return "stream_id";
231     case GRPC_ERROR_INT_GRPC_STATUS:
232       return "grpc_status";
233     case GRPC_ERROR_INT_OFFSET:
234       return "offset";
235     case GRPC_ERROR_INT_INDEX:
236       return "index";
237     case GRPC_ERROR_INT_SIZE:
238       return "size";
239     case GRPC_ERROR_INT_HTTP2_ERROR:
240       return "http2_error";
241     case GRPC_ERROR_INT_TSI_CODE:
242       return "tsi_code";
243     case GRPC_ERROR_INT_FD:
244       return "fd";
245     case GRPC_ERROR_INT_WSA_ERROR:
246       return "wsa_error";
247     case GRPC_ERROR_INT_HTTP_STATUS:
248       return "http_status";
249     case GRPC_ERROR_INT_OCCURRED_DURING_WRITE:
250       return "occurred_during_write";
251     case GRPC_ERROR_INT_CHANNEL_CONNECTIVITY_STATE:
252       return "channel_connectivity_state";
253     case GRPC_ERROR_INT_LB_POLICY_DROP:
254       return "lb_policy_drop";
255     case GRPC_ERROR_INT_MAX:
256       GPR_UNREACHABLE_CODE(return "unknown");
257   }
258   GPR_UNREACHABLE_CODE(return "unknown");
259 }
260 
error_str_name(grpc_error_strs key)261 static const char* error_str_name(grpc_error_strs key) {
262   switch (key) {
263     case GRPC_ERROR_STR_KEY:
264       return "key";
265     case GRPC_ERROR_STR_VALUE:
266       return "value";
267     case GRPC_ERROR_STR_DESCRIPTION:
268       return "description";
269     case GRPC_ERROR_STR_OS_ERROR:
270       return "os_error";
271     case GRPC_ERROR_STR_TARGET_ADDRESS:
272       return "target_address";
273     case GRPC_ERROR_STR_SYSCALL:
274       return "syscall";
275     case GRPC_ERROR_STR_FILE:
276       return "file";
277     case GRPC_ERROR_STR_GRPC_MESSAGE:
278       return "grpc_message";
279     case GRPC_ERROR_STR_RAW_BYTES:
280       return "raw_bytes";
281     case GRPC_ERROR_STR_TSI_ERROR:
282       return "tsi_error";
283     case GRPC_ERROR_STR_FILENAME:
284       return "filename";
285     case GRPC_ERROR_STR_MAX:
286       GPR_UNREACHABLE_CODE(return "unknown");
287   }
288   GPR_UNREACHABLE_CODE(return "unknown");
289 }
290 
error_time_name(grpc_error_times key)291 static const char* error_time_name(grpc_error_times key) {
292   switch (key) {
293     case GRPC_ERROR_TIME_CREATED:
294       return "created";
295     case GRPC_ERROR_TIME_MAX:
296       GPR_UNREACHABLE_CODE(return "unknown");
297   }
298   GPR_UNREACHABLE_CODE(return "unknown");
299 }
300 
301 #ifndef NDEBUG
grpc_error_do_ref(grpc_error_handle err,const char * file,int line)302 grpc_error_handle grpc_error_do_ref(grpc_error_handle err, const char* file,
303                                     int line) {
304   if (grpc_trace_error_refcount.enabled()) {
305     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
306             gpr_atm_no_barrier_load(&err->atomics.refs.count),
307             gpr_atm_no_barrier_load(&err->atomics.refs.count) + 1, file, line);
308   }
309   gpr_ref(&err->atomics.refs);
310   return err;
311 }
312 #else
grpc_error_do_ref(grpc_error_handle err)313 grpc_error_handle grpc_error_do_ref(grpc_error_handle err) {
314   gpr_ref(&err->atomics.refs);
315   return err;
316 }
317 #endif
318 
unref_errs(grpc_error_handle err)319 static void unref_errs(grpc_error_handle err) {
320   uint8_t slot = err->first_err;
321   while (slot != UINT8_MAX) {
322     grpc_linked_error* lerr =
323         reinterpret_cast<grpc_linked_error*>(err->arena + slot);
324     GRPC_ERROR_UNREF(lerr->err);
325     GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
326                                      : lerr->next != UINT8_MAX);
327     slot = lerr->next;
328   }
329 }
330 
unref_strs(grpc_error_handle err)331 static void unref_strs(grpc_error_handle err) {
332   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
333     uint8_t slot = err->strs[which];
334     if (slot != UINT8_MAX) {
335       grpc_slice_unref_internal(
336           *reinterpret_cast<grpc_slice*>(err->arena + slot));
337     }
338   }
339 }
340 
error_destroy(grpc_error_handle err)341 static void error_destroy(grpc_error_handle err) {
342   GPR_ASSERT(!grpc_error_is_special(err));
343   unref_errs(err);
344   unref_strs(err);
345   gpr_free(
346       reinterpret_cast<void*>(gpr_atm_acq_load(&err->atomics.error_string)));
347   gpr_free(err);
348 }
349 
350 #ifndef NDEBUG
grpc_error_do_unref(grpc_error_handle err,const char * file,int line)351 void grpc_error_do_unref(grpc_error_handle err, const char* file, int line) {
352   if (grpc_trace_error_refcount.enabled()) {
353     gpr_log(GPR_DEBUG, "%p: %" PRIdPTR " -> %" PRIdPTR " [%s:%d]", err,
354             gpr_atm_no_barrier_load(&err->atomics.refs.count),
355             gpr_atm_no_barrier_load(&err->atomics.refs.count) - 1, file, line);
356   }
357   if (gpr_unref(&err->atomics.refs)) {
358     error_destroy(err);
359   }
360 }
361 #else
grpc_error_do_unref(grpc_error_handle err)362 void grpc_error_do_unref(grpc_error_handle err) {
363   if (gpr_unref(&err->atomics.refs)) {
364     error_destroy(err);
365   }
366 }
367 #endif
368 
get_placement(grpc_error_handle * err,size_t size)369 static uint8_t get_placement(grpc_error_handle* err, size_t size) {
370   GPR_ASSERT(*err);
371   uint8_t slots = static_cast<uint8_t>(size / sizeof(intptr_t));
372   if ((*err)->arena_size + slots > (*err)->arena_capacity) {
373     (*err)->arena_capacity = static_cast<uint8_t>(std::min(
374         size_t(UINT8_MAX - 1), size_t(3 * (*err)->arena_capacity / 2)));
375     if ((*err)->arena_size + slots > (*err)->arena_capacity) {
376       return UINT8_MAX;
377     }
378 #ifndef NDEBUG
379     grpc_error_handle orig = *err;
380 #endif
381     *err = static_cast<grpc_error_handle>(gpr_realloc(
382         *err, sizeof(grpc_error) + (*err)->arena_capacity * sizeof(intptr_t)));
383 #ifndef NDEBUG
384     if (grpc_trace_error_refcount.enabled()) {
385       if (*err != orig) {
386         gpr_log(GPR_DEBUG, "realloc %p -> %p", orig, *err);
387       }
388     }
389 #endif
390   }
391   uint8_t placement = (*err)->arena_size;
392   (*err)->arena_size = static_cast<uint8_t>((*err)->arena_size + slots);
393   return placement;
394 }
395 
internal_set_int(grpc_error_handle * err,grpc_error_ints which,intptr_t value)396 static void internal_set_int(grpc_error_handle* err, grpc_error_ints which,
397                              intptr_t value) {
398   uint8_t slot = (*err)->ints[which];
399   if (slot == UINT8_MAX) {
400     slot = get_placement(err, sizeof(value));
401     if (slot == UINT8_MAX) {
402       gpr_log(GPR_ERROR, "Error %p is full, dropping int {\"%s\":%" PRIiPTR "}",
403               *err, error_int_name(which), value);
404       return;
405     }
406   }
407   (*err)->ints[which] = slot;
408   (*err)->arena[slot] = value;
409 }
410 
internal_set_str(grpc_error_handle * err,grpc_error_strs which,const grpc_slice & value)411 static void internal_set_str(grpc_error_handle* err, grpc_error_strs which,
412                              const grpc_slice& value) {
413   uint8_t slot = (*err)->strs[which];
414   if (slot == UINT8_MAX) {
415     slot = get_placement(err, sizeof(value));
416     if (slot == UINT8_MAX) {
417       char* str = grpc_slice_to_c_string(value);
418       gpr_log(GPR_ERROR, "Error %p is full, dropping string {\"%s\":\"%s\"}",
419               *err, error_str_name(which), str);
420       gpr_free(str);
421       return;
422     }
423   } else {
424     grpc_slice_unref_internal(
425         *reinterpret_cast<grpc_slice*>((*err)->arena + slot));
426   }
427   (*err)->strs[which] = slot;
428   memcpy((*err)->arena + slot, &value, sizeof(value));
429 }
430 
431 static char* fmt_time(gpr_timespec tm);
internal_set_time(grpc_error_handle * err,grpc_error_times which,gpr_timespec value)432 static void internal_set_time(grpc_error_handle* err, grpc_error_times which,
433                               gpr_timespec value) {
434   uint8_t slot = (*err)->times[which];
435   if (slot == UINT8_MAX) {
436     slot = get_placement(err, sizeof(value));
437     if (slot == UINT8_MAX) {
438       char* time_str = fmt_time(value);
439       gpr_log(GPR_ERROR, "Error %p is full, dropping \"%s\":\"%s\"}", *err,
440               error_time_name(which), time_str);
441       gpr_free(time_str);
442       return;
443     }
444   }
445   (*err)->times[which] = slot;
446   memcpy((*err)->arena + slot, &value, sizeof(value));
447 }
448 
internal_add_error(grpc_error_handle * err,grpc_error_handle new_err)449 static void internal_add_error(grpc_error_handle* err,
450                                grpc_error_handle new_err) {
451   grpc_linked_error new_last = {new_err, UINT8_MAX};
452   uint8_t slot = get_placement(err, sizeof(grpc_linked_error));
453   if (slot == UINT8_MAX) {
454     gpr_log(GPR_ERROR, "Error %p is full, dropping error %p = %s", *err,
455             new_err, grpc_error_string(new_err));
456     GRPC_ERROR_UNREF(new_err);
457     return;
458   }
459   if ((*err)->first_err == UINT8_MAX) {
460     GPR_ASSERT((*err)->last_err == UINT8_MAX);
461     (*err)->last_err = slot;
462     (*err)->first_err = slot;
463   } else {
464     GPR_ASSERT((*err)->last_err != UINT8_MAX);
465     grpc_linked_error* old_last =
466         reinterpret_cast<grpc_linked_error*>((*err)->arena + (*err)->last_err);
467     old_last->next = slot;
468     (*err)->last_err = slot;
469   }
470   memcpy((*err)->arena + slot, &new_last, sizeof(grpc_linked_error));
471 }
472 
473 #define SLOTS_PER_INT (1)  // == (sizeof(intptr_t) / sizeof(intptr_t))
474 #define SLOTS_PER_STR (sizeof(grpc_slice) / sizeof(intptr_t))
475 #define SLOTS_PER_TIME (sizeof(gpr_timespec) / sizeof(intptr_t))
476 #define SLOTS_PER_LINKED_ERROR (sizeof(grpc_linked_error) / sizeof(intptr_t))
477 
478 // size of storing one int and two slices and a timespec. For line, desc, file,
479 // and time created
480 #define DEFAULT_ERROR_CAPACITY \
481   (SLOTS_PER_INT + (SLOTS_PER_STR * 2) + SLOTS_PER_TIME)
482 
483 // It is very common to include and extra int and string in an error
484 #define SURPLUS_CAPACITY (2 * SLOTS_PER_INT + SLOTS_PER_TIME)
485 
grpc_error_create(const char * file,int line,const grpc_slice & desc,grpc_error_handle * referencing,size_t num_referencing)486 grpc_error_handle grpc_error_create(const char* file, int line,
487                                     const grpc_slice& desc,
488                                     grpc_error_handle* referencing,
489                                     size_t num_referencing) {
490   uint8_t initial_arena_capacity = static_cast<uint8_t>(
491       DEFAULT_ERROR_CAPACITY +
492       static_cast<uint8_t>(num_referencing * SLOTS_PER_LINKED_ERROR) +
493       SURPLUS_CAPACITY);
494   grpc_error_handle err = static_cast<grpc_error_handle>(
495       gpr_malloc(sizeof(*err) + initial_arena_capacity * sizeof(intptr_t)));
496   if (err == nullptr) {  // TODO(ctiller): make gpr_malloc return NULL
497     return GRPC_ERROR_OOM;
498   }
499 #ifndef NDEBUG
500   if (!gpr_atm_no_barrier_load(&g_error_creation_allowed)) {
501     gpr_log(GPR_ERROR,
502             "Error creation occurred when error creation was disabled [%s:%d]",
503             file, line);
504     abort();
505   }
506   if (grpc_trace_error_refcount.enabled()) {
507     gpr_log(GPR_DEBUG, "%p create [%s:%d]", err, file, line);
508   }
509 #endif
510 
511   err->arena_size = 0;
512   err->arena_capacity = initial_arena_capacity;
513   err->first_err = UINT8_MAX;
514   err->last_err = UINT8_MAX;
515 
516   memset(err->ints, UINT8_MAX, GRPC_ERROR_INT_MAX);
517   memset(err->strs, UINT8_MAX, GRPC_ERROR_STR_MAX);
518   memset(err->times, UINT8_MAX, GRPC_ERROR_TIME_MAX);
519 
520   internal_set_int(&err, GRPC_ERROR_INT_FILE_LINE, line);
521   internal_set_str(&err, GRPC_ERROR_STR_FILE,
522                    grpc_slice_from_static_string(file));
523   internal_set_str(&err, GRPC_ERROR_STR_DESCRIPTION, desc);
524 
525   for (size_t i = 0; i < num_referencing; ++i) {
526     if (referencing[i] == GRPC_ERROR_NONE) continue;
527     internal_add_error(
528         &err,
529         GRPC_ERROR_REF(
530             referencing[i]));  // TODO(ncteisen), change ownership semantics
531   }
532 
533   internal_set_time(&err, GRPC_ERROR_TIME_CREATED, gpr_now(GPR_CLOCK_REALTIME));
534 
535   gpr_atm_no_barrier_store(&err->atomics.error_string, 0);
536   gpr_ref_init(&err->atomics.refs, 1);
537   return err;
538 }
539 
ref_strs(grpc_error_handle err)540 static void ref_strs(grpc_error_handle err) {
541   for (size_t i = 0; i < GRPC_ERROR_STR_MAX; ++i) {
542     uint8_t slot = err->strs[i];
543     if (slot != UINT8_MAX) {
544       grpc_slice_ref_internal(
545           *reinterpret_cast<grpc_slice*>(err->arena + slot));
546     }
547   }
548 }
549 
ref_errs(grpc_error_handle err)550 static void ref_errs(grpc_error_handle err) {
551   uint8_t slot = err->first_err;
552   while (slot != UINT8_MAX) {
553     grpc_linked_error* lerr =
554         reinterpret_cast<grpc_linked_error*>(err->arena + slot);
555     (void)GRPC_ERROR_REF(lerr->err);
556     slot = lerr->next;
557   }
558 }
559 
copy_error_and_unref(grpc_error_handle in)560 static grpc_error_handle copy_error_and_unref(grpc_error_handle in) {
561   grpc_error_handle out;
562   if (grpc_error_is_special(in)) {
563     out = GRPC_ERROR_CREATE_FROM_STATIC_STRING("unknown");
564     if (in == GRPC_ERROR_NONE) {
565       internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
566                        grpc_slice_from_static_string("no error"));
567       internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_OK);
568     } else if (in == GRPC_ERROR_OOM) {
569       internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
570                        grpc_slice_from_static_string("oom"));
571     } else if (in == GRPC_ERROR_CANCELLED) {
572       internal_set_str(&out, GRPC_ERROR_STR_DESCRIPTION,
573                        grpc_slice_from_static_string("cancelled"));
574       internal_set_int(&out, GRPC_ERROR_INT_GRPC_STATUS, GRPC_STATUS_CANCELLED);
575     }
576   } else if (gpr_ref_is_unique(&in->atomics.refs)) {
577     out = in;
578   } else {
579     uint8_t new_arena_capacity = in->arena_capacity;
580     // the returned err will be added to, so we ensure this is room to avoid
581     // unneeded allocations.
582     if (in->arena_capacity - in->arena_size <
583         static_cast<uint8_t> SLOTS_PER_STR) {
584       new_arena_capacity = static_cast<uint8_t>(3 * new_arena_capacity / 2);
585     }
586     out = static_cast<grpc_error_handle>(
587         gpr_malloc(sizeof(*in) + new_arena_capacity * sizeof(intptr_t)));
588 #ifndef NDEBUG
589     if (grpc_trace_error_refcount.enabled()) {
590       gpr_log(GPR_DEBUG, "%p create copying %p", out, in);
591     }
592 #endif
593     // bulk memcpy of the rest of the struct.
594     // NOLINTNEXTLINE(bugprone-sizeof-expression)
595     size_t skip = sizeof(&out->atomics);
596     memcpy(reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(out) + skip),
597            reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(in) + skip),
598            sizeof(*in) + (in->arena_size * sizeof(intptr_t)) - skip);
599     // manually set the atomics and the new capacity
600     gpr_atm_no_barrier_store(&out->atomics.error_string, 0);
601     gpr_ref_init(&out->atomics.refs, 1);
602     out->arena_capacity = new_arena_capacity;
603     ref_strs(out);
604     ref_errs(out);
605     GRPC_ERROR_UNREF(in);
606   }
607   return out;
608 }
609 
grpc_error_set_int(grpc_error_handle src,grpc_error_ints which,intptr_t value)610 grpc_error_handle grpc_error_set_int(grpc_error_handle src,
611                                      grpc_error_ints which, intptr_t value) {
612   grpc_error_handle new_err = copy_error_and_unref(src);
613   internal_set_int(&new_err, which, value);
614   return new_err;
615 }
616 
617 struct special_error_status_map {
618   grpc_status_code code;
619   const char* msg;
620   size_t len;
621 };
622 const special_error_status_map error_status_map[] = {
623     {GRPC_STATUS_OK, "", 0},                // GRPC_ERROR_NONE
624     {GRPC_STATUS_INVALID_ARGUMENT, "", 0},  // GRPC_ERROR_RESERVED_1
625     {GRPC_STATUS_RESOURCE_EXHAUSTED, "RESOURCE_EXHAUSTED",
626      strlen("RESOURCE_EXHAUSTED")},         // GRPC_ERROR_OOM
627     {GRPC_STATUS_INVALID_ARGUMENT, "", 0},  // GRPC_ERROR_RESERVED_2
628     {GRPC_STATUS_CANCELLED, "CANCELLED",
629      strlen("CANCELLED")},  // GRPC_ERROR_CANCELLED
630 };
631 
grpc_error_get_int(grpc_error_handle err,grpc_error_ints which,intptr_t * p)632 bool grpc_error_get_int(grpc_error_handle err, grpc_error_ints which,
633                         intptr_t* p) {
634   if (grpc_error_is_special(err)) {
635     if (which != GRPC_ERROR_INT_GRPC_STATUS) return false;
636     *p = error_status_map[reinterpret_cast<size_t>(err)].code;
637     return true;
638   }
639   uint8_t slot = err->ints[which];
640   if (slot != UINT8_MAX) {
641     if (p != nullptr) *p = err->arena[slot];
642     return true;
643   }
644   return false;
645 }
646 
grpc_error_set_str(grpc_error_handle src,grpc_error_strs which,absl::string_view str)647 grpc_error_handle grpc_error_set_str(grpc_error_handle src,
648                                      grpc_error_strs which,
649                                      absl::string_view str) {
650   grpc_error_handle new_err = copy_error_and_unref(src);
651   internal_set_str(&new_err, which,
652                    grpc_slice_from_copied_buffer(str.data(), str.length()));
653   return new_err;
654 }
655 
grpc_error_get_str(grpc_error_handle err,grpc_error_strs which,std::string * s)656 bool grpc_error_get_str(grpc_error_handle err, grpc_error_strs which,
657                         std::string* s) {
658   if (grpc_error_is_special(err)) {
659     if (which != GRPC_ERROR_STR_GRPC_MESSAGE) return false;
660     const special_error_status_map& msg =
661         error_status_map[reinterpret_cast<size_t>(err)];
662     *s = std::string(msg.msg, msg.len);
663     return true;
664   }
665   uint8_t slot = err->strs[which];
666   if (slot != UINT8_MAX) {
667     grpc_slice* slice = reinterpret_cast<grpc_slice*>(err->arena + slot);
668     *s = std::string(grpc_core::StringViewFromSlice(*slice));
669     return true;
670   } else {
671     return false;
672   }
673 }
674 
grpc_error_add_child(grpc_error_handle src,grpc_error_handle child)675 grpc_error_handle grpc_error_add_child(grpc_error_handle src,
676                                        grpc_error_handle child) {
677   if (src != GRPC_ERROR_NONE) {
678     if (child == GRPC_ERROR_NONE) {
679       /* \a child is empty. Simply return the ref to \a src */
680       return src;
681     } else if (child != src) {
682       grpc_error_handle new_err = copy_error_and_unref(src);
683       internal_add_error(&new_err, child);
684       return new_err;
685     } else {
686       /* \a src and \a child are the same. Drop one of the references and return
687        * the other */
688       GRPC_ERROR_UNREF(child);
689       return src;
690     }
691   } else {
692     /* \a src is empty. Simply return the ref to \a child */
693     return child;
694   }
695 }
696 
697 static const char* no_error_string = "\"OK\"";
698 static const char* oom_error_string = "\"RESOURCE_EXHAUSTED\"";
699 static const char* cancelled_error_string = "\"CANCELLED\"";
700 
701 struct kv_pair {
702   char* key;
703   char* value;
704 };
705 struct kv_pairs {
706   kv_pair* kvs;
707   size_t num_kvs;
708   size_t cap_kvs;
709 };
append_chr(char c,char ** s,size_t * sz,size_t * cap)710 static void append_chr(char c, char** s, size_t* sz, size_t* cap) {
711   if (*sz == *cap) {
712     *cap = std::max(size_t(8), 3 * *cap / 2);
713     *s = static_cast<char*>(gpr_realloc(*s, *cap));
714   }
715   (*s)[(*sz)++] = c;
716 }
717 
append_str(const char * str,char ** s,size_t * sz,size_t * cap)718 static void append_str(const char* str, char** s, size_t* sz, size_t* cap) {
719   for (const char* c = str; *c; c++) {
720     append_chr(*c, s, sz, cap);
721   }
722 }
723 
append_esc_str(const uint8_t * str,size_t len,char ** s,size_t * sz,size_t * cap)724 static void append_esc_str(const uint8_t* str, size_t len, char** s, size_t* sz,
725                            size_t* cap) {
726   static const char* hex = "0123456789abcdef";
727   append_chr('"', s, sz, cap);
728   for (size_t i = 0; i < len; i++, str++) {
729     if (*str < 32 || *str >= 127) {
730       append_chr('\\', s, sz, cap);
731       switch (*str) {
732         case '\b':
733           append_chr('b', s, sz, cap);
734           break;
735         case '\f':
736           append_chr('f', s, sz, cap);
737           break;
738         case '\n':
739           append_chr('n', s, sz, cap);
740           break;
741         case '\r':
742           append_chr('r', s, sz, cap);
743           break;
744         case '\t':
745           append_chr('t', s, sz, cap);
746           break;
747         default:
748           append_chr('u', s, sz, cap);
749           append_chr('0', s, sz, cap);
750           append_chr('0', s, sz, cap);
751           append_chr(hex[*str >> 4], s, sz, cap);
752           append_chr(hex[*str & 0x0f], s, sz, cap);
753           break;
754       }
755     } else {
756       append_chr(static_cast<char>(*str), s, sz, cap);
757     }
758   }
759   append_chr('"', s, sz, cap);
760 }
761 
append_kv(kv_pairs * kvs,char * key,char * value)762 static void append_kv(kv_pairs* kvs, char* key, char* value) {
763   if (kvs->num_kvs == kvs->cap_kvs) {
764     kvs->cap_kvs = std::max(3 * kvs->cap_kvs / 2, size_t(4));
765     kvs->kvs = static_cast<kv_pair*>(
766         gpr_realloc(kvs->kvs, sizeof(*kvs->kvs) * kvs->cap_kvs));
767   }
768   kvs->kvs[kvs->num_kvs].key = key;
769   kvs->kvs[kvs->num_kvs].value = value;
770   kvs->num_kvs++;
771 }
772 
key_int(grpc_error_ints which)773 static char* key_int(grpc_error_ints which) {
774   return gpr_strdup(error_int_name(which));
775 }
776 
fmt_int(intptr_t p)777 static char* fmt_int(intptr_t p) {
778   char* s;
779   gpr_asprintf(&s, "%" PRIdPTR, p);
780   return s;
781 }
782 
collect_ints_kvs(grpc_error_handle err,kv_pairs * kvs)783 static void collect_ints_kvs(grpc_error_handle err, kv_pairs* kvs) {
784   for (size_t which = 0; which < GRPC_ERROR_INT_MAX; ++which) {
785     uint8_t slot = err->ints[which];
786     if (slot != UINT8_MAX) {
787       append_kv(kvs, key_int(static_cast<grpc_error_ints>(which)),
788                 fmt_int(err->arena[slot]));
789     }
790   }
791 }
792 
key_str(grpc_error_strs which)793 static char* key_str(grpc_error_strs which) {
794   return gpr_strdup(error_str_name(which));
795 }
796 
fmt_str(const grpc_slice & slice)797 static char* fmt_str(const grpc_slice& slice) {
798   char* s = nullptr;
799   size_t sz = 0;
800   size_t cap = 0;
801   append_esc_str(GRPC_SLICE_START_PTR(slice), GRPC_SLICE_LENGTH(slice), &s, &sz,
802                  &cap);
803   append_chr(0, &s, &sz, &cap);
804   return s;
805 }
806 
collect_strs_kvs(grpc_error_handle err,kv_pairs * kvs)807 static void collect_strs_kvs(grpc_error_handle err, kv_pairs* kvs) {
808   for (size_t which = 0; which < GRPC_ERROR_STR_MAX; ++which) {
809     uint8_t slot = err->strs[which];
810     if (slot != UINT8_MAX) {
811       append_kv(kvs, key_str(static_cast<grpc_error_strs>(which)),
812                 fmt_str(*reinterpret_cast<grpc_slice*>(err->arena + slot)));
813     }
814   }
815 }
816 
key_time(grpc_error_times which)817 static char* key_time(grpc_error_times which) {
818   return gpr_strdup(error_time_name(which));
819 }
820 
fmt_time(gpr_timespec tm)821 static char* fmt_time(gpr_timespec tm) {
822   char* out;
823   const char* pfx = "!!";
824   switch (tm.clock_type) {
825     case GPR_CLOCK_MONOTONIC:
826       pfx = "@monotonic:";
827       break;
828     case GPR_CLOCK_REALTIME:
829       pfx = "@";
830       break;
831     case GPR_CLOCK_PRECISE:
832       pfx = "@precise:";
833       break;
834     case GPR_TIMESPAN:
835       pfx = "";
836       break;
837   }
838   gpr_asprintf(&out, "\"%s%" PRId64 ".%09d\"", pfx, tm.tv_sec, tm.tv_nsec);
839   return out;
840 }
841 
collect_times_kvs(grpc_error_handle err,kv_pairs * kvs)842 static void collect_times_kvs(grpc_error_handle err, kv_pairs* kvs) {
843   for (size_t which = 0; which < GRPC_ERROR_TIME_MAX; ++which) {
844     uint8_t slot = err->times[which];
845     if (slot != UINT8_MAX) {
846       append_kv(kvs, key_time(static_cast<grpc_error_times>(which)),
847                 fmt_time(*reinterpret_cast<gpr_timespec*>(err->arena + slot)));
848     }
849   }
850 }
851 
add_errs(grpc_error_handle err,char ** s,size_t * sz,size_t * cap)852 static void add_errs(grpc_error_handle err, char** s, size_t* sz, size_t* cap) {
853   uint8_t slot = err->first_err;
854   bool first = true;
855   while (slot != UINT8_MAX) {
856     grpc_linked_error* lerr =
857         reinterpret_cast<grpc_linked_error*>(err->arena + slot);
858     if (!first) append_chr(',', s, sz, cap);
859     first = false;
860     const char* e = grpc_error_string(lerr->err);
861     append_str(e, s, sz, cap);
862     GPR_ASSERT(err->last_err == slot ? lerr->next == UINT8_MAX
863                                      : lerr->next != UINT8_MAX);
864     slot = lerr->next;
865   }
866 }
867 
errs_string(grpc_error_handle err)868 static char* errs_string(grpc_error_handle err) {
869   char* s = nullptr;
870   size_t sz = 0;
871   size_t cap = 0;
872   append_chr('[', &s, &sz, &cap);
873   add_errs(err, &s, &sz, &cap);
874   append_chr(']', &s, &sz, &cap);
875   append_chr(0, &s, &sz, &cap);
876   return s;
877 }
878 
cmp_kvs(const void * a,const void * b)879 static int cmp_kvs(const void* a, const void* b) {
880   const kv_pair* ka = static_cast<const kv_pair*>(a);
881   const kv_pair* kb = static_cast<const kv_pair*>(b);
882   return strcmp(ka->key, kb->key);
883 }
884 
finish_kvs(kv_pairs * kvs)885 static char* finish_kvs(kv_pairs* kvs) {
886   char* s = nullptr;
887   size_t sz = 0;
888   size_t cap = 0;
889 
890   append_chr('{', &s, &sz, &cap);
891   for (size_t i = 0; i < kvs->num_kvs; i++) {
892     if (i != 0) append_chr(',', &s, &sz, &cap);
893     append_esc_str(reinterpret_cast<const uint8_t*>(kvs->kvs[i].key),
894                    strlen(kvs->kvs[i].key), &s, &sz, &cap);
895     gpr_free(kvs->kvs[i].key);
896     append_chr(':', &s, &sz, &cap);
897     append_str(kvs->kvs[i].value, &s, &sz, &cap);
898     gpr_free(kvs->kvs[i].value);
899   }
900   append_chr('}', &s, &sz, &cap);
901   append_chr(0, &s, &sz, &cap);
902 
903   gpr_free(kvs->kvs);
904   return s;
905 }
906 
grpc_error_string(grpc_error_handle err)907 const char* grpc_error_string(grpc_error_handle err) {
908   if (err == GRPC_ERROR_NONE) return no_error_string;
909   if (err == GRPC_ERROR_OOM) return oom_error_string;
910   if (err == GRPC_ERROR_CANCELLED) return cancelled_error_string;
911 
912   void* p =
913       reinterpret_cast<void*>(gpr_atm_acq_load(&err->atomics.error_string));
914   if (p != nullptr) {
915     return static_cast<const char*>(p);
916   }
917 
918   kv_pairs kvs;
919   memset(&kvs, 0, sizeof(kvs));
920 
921   collect_ints_kvs(err, &kvs);
922   collect_strs_kvs(err, &kvs);
923   collect_times_kvs(err, &kvs);
924   if (err->first_err != UINT8_MAX) {
925     append_kv(&kvs, gpr_strdup("referenced_errors"), errs_string(err));
926   }
927 
928   qsort(kvs.kvs, kvs.num_kvs, sizeof(kv_pair), cmp_kvs);
929 
930   char* out = finish_kvs(&kvs);
931 
932   if (!gpr_atm_rel_cas(&err->atomics.error_string, 0,
933                        reinterpret_cast<gpr_atm>(out))) {
934     gpr_free(out);
935     out = reinterpret_cast<char*>(gpr_atm_acq_load(&err->atomics.error_string));
936   }
937 
938   return out;
939 }
940 
grpc_error_std_string(grpc_error_handle error)941 std::string grpc_error_std_string(grpc_error_handle error) {
942   return std::string(grpc_error_string(error));
943 }
944 
grpc_os_error(const char * file,int line,int err,const char * call_name)945 grpc_error_handle grpc_os_error(const char* file, int line, int err,
946                                 const char* call_name) {
947   return grpc_error_set_str(
948       grpc_error_set_str(
949           grpc_error_set_int(
950               grpc_error_create(file, line,
951                                 grpc_slice_from_static_string(strerror(err)),
952                                 nullptr, 0),
953               GRPC_ERROR_INT_ERRNO, err),
954           GRPC_ERROR_STR_OS_ERROR, strerror(err)),
955       GRPC_ERROR_STR_SYSCALL, call_name);
956 }
957 
958 #ifdef GPR_WINDOWS
grpc_wsa_error(const char * file,int line,int err,const char * call_name)959 grpc_error_handle grpc_wsa_error(const char* file, int line, int err,
960                                  const char* call_name) {
961   char* utf8_message = gpr_format_message(err);
962   grpc_error_handle error = grpc_error_set_str(
963       grpc_error_set_str(
964           grpc_error_set_int(
965               grpc_error_create(file, line,
966                                 grpc_slice_from_static_string("OS Error"), NULL,
967                                 0),
968               GRPC_ERROR_INT_WSA_ERROR, err),
969           GRPC_ERROR_STR_OS_ERROR, utf8_message),
970       GRPC_ERROR_STR_SYSCALL, call_name);
971   gpr_free(utf8_message);
972   return error;
973 }
974 #endif
975 
grpc_log_error(const char * what,grpc_error_handle error,const char * file,int line)976 bool grpc_log_error(const char* what, grpc_error_handle error, const char* file,
977                     int line) {
978   GPR_DEBUG_ASSERT(error != GRPC_ERROR_NONE);
979   const char* msg = grpc_error_string(error);
980   gpr_log(file, line, GPR_LOG_SEVERITY_ERROR, "%s: %s", what, msg);
981   GRPC_ERROR_UNREF(error);
982   return false;
983 }
984 
985 #endif  // GRPC_ERROR_IS_ABSEIL_STATUS
986