• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# gRPC Error
2
3## Background
4
5`grpc_error` is the c-core's opaque representation of an error. It holds a
6collection of integers, strings, timestamps, and child errors that related to
7the final error.
8
9always present are:
10
11*   GRPC_ERROR_STR_FILE and GRPC_ERROR_INT_FILE_LINE - the source location where
12    the error was generated
13*   GRPC_ERROR_STR_DESCRIPTION - a human readable description of the error
14*   GRPC_ERROR_TIME_CREATED - a timestamp indicating when the error happened
15
16An error can also have children; these are other errors that are believed to
17have contributed to this one. By accumulating children, we can begin to root
18cause high level failures from low level failures, without having to derive
19execution paths from log lines.
20
21grpc_errors are refcounted objects, which means they need strict ownership
22semantics. An extra ref on an error can cause a memory leak, and a missing ref
23can cause a crash.
24
25This document serves as a detailed overview of grpc_error's ownership rules. It
26should help people use the errors, as well as help people debug refcount related
27errors.
28
29## Clarification of Ownership
30
31If a particular function is said to "own" an error, that means it has the
32responsibility of calling unref on the error. A function may have access to an
33error without ownership of it.
34
35This means the function may use the error, but must not call unref on it, since
36that will be done elsewhere in the code. A function that does not own an error
37may explicitly take ownership of it by manually calling GRPC_ERROR_REF.
38
39## Ownership Rules
40
41There are three rules of error ownership, which we will go over in detail.
42
43*   If `grpc_error` is returned by a function, the caller owns a ref to that
44    instance.
45*   If a `grpc_error` is passed to a `grpc_closure` callback function, then that
46    function does not own a ref to the error.
47*   if a `grpc_error` is passed to *any other function*, then that function
48    takes ownership of the error.
49
50### Rule 1
51
52> If `grpc_error` is returned by a function, the caller owns a ref to that
53> instance.*
54
55For example, in the following code block, error1 and error2 are owned by the
56current function.
57
58```C
59grpc_error* error1 = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
60grpc_error* error2 = some_operation_that_might_fail(...);
61```
62
63The current function would have to explicitly call GRPC_ERROR_UNREF on the
64errors, or pass them along to a function that would take over the ownership.
65
66### Rule 2
67
68> If a `grpc_error` is passed to a `grpc_closure` callback function, then that
69> function does not own a ref to the error.
70
71A `grpc_closure` callback function is any function that has the signature:
72
73```C
74void (*cb)(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error);
75```
76
77This means that the error ownership is NOT transferred when a functions calls:
78
79```C
80c->cb(exec_ctx, c->cb_arg, err);
81```
82
83The caller is still responsible for unref-ing the error.
84
85However, the above line is currently being phased out! It is safer to invoke
86callbacks with `GRPC_CLOSURE_RUN` and `GRPC_CLOSURE_SCHED`. These functions are
87not callbacks, so they will take ownership of the error passed to them.
88
89```C
90grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
91GRPC_CLOSURE_RUN(exec_ctx, cb, error);
92// current function no longer has ownership of the error
93```
94
95If you schedule or run a closure, but still need ownership of the error, then
96you must explicitly take a reference.
97
98```C
99grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
100GRPC_CLOSURE_RUN(exec_ctx, cb, GRPC_ERROR_REF(error));
101// do some other things with the error
102GRPC_ERROR_UNREF(error);
103```
104
105Rule 2 is more important to keep in mind when **implementing** `grpc_closure`
106callback functions. You must keep in mind that you do not own the error, and
107must not unref it. More importantly, you cannot pass it to any function that
108would take ownership of the error, without explicitly taking ownership yourself.
109For example:
110
111```C
112void on_some_action(grpc_exec_ctx *exec_ctx, void *arg, grpc_error *error) {
113  // this would cause a crash, because some_function will unref the error,
114  // and the caller of this callback will also unref it.
115  some_function(error);
116
117  // this callback function must take ownership, so it can give that
118  // ownership to the function it is calling.
119  some_function(GRPC_ERROR_REF(error));
120}
121```
122
123### Rule 3
124
125> if a `grpc_error` is passed to *any other function*, then that function takes
126> ownership of the error.
127
128Take the following example:
129
130```C
131grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error occurred");
132// do some things
133some_function(error);
134// can't use error anymore! might be gone.
135```
136
137When some_function is called, it takes over the ownership of the error, and it
138will eventually unref it. So the caller can no longer safely use the error.
139
140If the caller needed to keep using the error (or passing it to other functions),
141if would have to take on a reference to it. This is a common pattern seen.
142
143```C
144void func() {
145  grpc_error* error = GRPC_ERROR_CREATE_FROM_STATIC_STRING("Some error");
146  some_function(GRPC_ERROR_REF(error));
147  // do things
148  some_other_function(GRPC_ERROR_REF(error));
149  // do more things
150  some_last_function(error);
151}
152```
153
154The last call takes ownership and will eventually give the error its final
155unref.
156
157When **implementing** a function that takes an error (and is not a
158`grpc_closure` callback function), you must ensure the error is unref-ed either
159by doing it explicitly with GRPC_ERROR_UNREF, or by passing the error to a
160function that takes over the ownership.
161