python:tests: Don’t needlessly create single‐element tuple
[Samba.git] / lib / talloc / doc / tutorial_bestpractices.dox
blob36344467433f9dadf47fd727160f5bd45dec52ce
1 /**
2 @page libtalloc_bestpractices Chapter 7: Best practises
4 The following sections contain several best practices and good manners that were
5 found by the <a href="http://www.samba.org">Samba</a> and
6 <a href="https://fedorahosted.org/sssd">SSSD</a> developers over the years.
7 These will help you to write code which is better, easier to debug and with as
8 few (hopefully none) memory leaks as possible.
10 @section bp-hierarchy Keep the context hierarchy steady
12 The talloc is a hierarchy memory allocator. The hierarchy nature is what makes
13 the programming more error proof. It makes the memory easier to manage and to
14 free.  Therefore, the first thing we should have on our mind is: always project
15 your data structures into the talloc context hierarchy.
17 That means if we have a structure, we should always use it as a parent context
18 for its elements. This way we will not encounter any troubles when freeing the
19 structure or when changing its parent. The same rule applies for arrays.
21 For example, the structure <code>user</code> from section @ref context-hierarchy
22 should be created with the context hierarchy illustrated on the next image.
24 @image html context_tree.png
26 @section bp-tmpctx Every function should use its own context
28 It is a good practice to create a temporary talloc context at the function
29 beginning and free the context just before the return statement. All the data
30 must be allocated on this context or on its children. This ensures that no
31 memory leaks are created as long as we do not forget to free the temporary
32 context.
34 This pattern applies to both situations - when a function does not return any
35 dynamically allocated value and when it does. However, it needs a little
36 extension for the latter case.
38 @subsection bp-tmpctx-1 Functions that do not return any dynamically allocated
39 value
41 If the function does not return any value created on the heap, we will just obey
42 the aforementioned pattern.
44 @code
45 int bar()
47   int ret;
48   TALLOC_CTX *tmp_ctx = talloc_new(NULL);
49   if (tmp_ctx == NULL) {
50     ret = ENOMEM;
51     goto done;
52   }
53   /* allocate data on tmp_ctx or on its descendants */
54   ret = EOK;
55 done:
56   talloc_free(tmp_ctx);
57   return ret;
59 @endcode
61 @subsection bp-tmpctx-2 Functions returning dynamically allocated values
63 If our function returns any dynamically allocated data, its first parameter
64 should always be the destination talloc context. This context serves as a parent
65 for the output values. But again, we will create the output values as the
66 descendants of the temporary context. If everything goes well, we will change
67 the parent of the output values from the temporary to the destination talloc
68 context.
70 This pattern ensures that if an error occurs (e.g. I/O error or insufficient
71 amount of the memory), all allocated data is freed and no garbage appears on
72 the destination context.
74 @code
75 int struct_foo_init(TALLOC_CTX *mem_ctx, struct foo **_foo)
77   int ret;
78   struct foo *foo = NULL;
79   TALLOC_CTX *tmp_ctx = talloc_new(NULL);
80   if (tmp_ctx == NULL) {
81     ret = ENOMEM;
82     goto done;
83   }
84   foo = talloc_zero(tmp_ctx, struct foo);
85   /* ... */
86   *_foo = talloc_steal(mem_ctx, foo);
87   ret = EOK;
88 done:
89   talloc_free(tmp_ctx);
90   return ret;
92 @endcode
94 @section bp-null Allocate temporary contexts on NULL
96 As it can be seen on the previous listing, instead of allocating the temporary
97 context directly on <code>mem_ctx</code>, we created a new top level context
98 using <code>NULL</code> as the parameter for <code>talloc_new()</code> function.
99 Take a look at the following example:
101 @code
102 char *create_user_filter(TALLOC_CTX *mem_ctx,
103                          uid_t uid, const char *username)
105   char *filter = NULL;
106   char *sanitized_username = NULL;
107   /* tmp_ctx is a child of mem_ctx */
108   TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
109   if (tmp_ctx == NULL) {
110     return NULL;
111   }
113   sanitized_username = sanitize_string(tmp_ctx, username);
114   if (sanitized_username == NULL) {
115     talloc_free(tmp_ctx);
116     return NULL;
117   }
119   filter = talloc_aprintf(tmp_ctx,"(|(uid=%llu)(uname=%s))",
120                           uid, sanitized_username);
121   if (filter == NULL) {
122     return NULL; /* tmp_ctx is not freed */ (*@\label{lst:tmp-ctx-3:leak}@*)
123   }
125   /* filter becomes a child of mem_ctx */
126   filter = talloc_steal(mem_ctx, filter);
127   talloc_free(tmp_ctx);
128   return filter;
130 @endcode
132 We forgot to free <code>tmp_ctx</code> before the <code>return</code> statement
133 in the <code>filter == NULL</code> condition. However, it is created as a child
134 of <code>mem_ctx</code> context and as such it will be freed as soon as the
135 <code>mem_ctx</code> is freed. Therefore, no detectable memory leak is created.
137 On the other hand, we do not have any way to access the allocated data
138 and for all we know <code>mem_ctx</code> may exist for the lifetime of our
139 application. For these reasons this should be considered as a memory leak. How
140 can we detect if it is unreferenced but still attached to its parent context?
141 The only way is to notice the mistake in the source code.
143 But if we create the temporary context as a top level context, it will not be
144 freed and memory diagnostic tools
145 (e.g. <a href="http://valgrind.org">valgrind</a>) are able to do their job.
147 @section bp-pool Temporary contexts and the talloc pool
149 If we want to take the advantage of the talloc pool but also keep to the
150 pattern introduced in the previous section, we are unable to do it directly. The
151 best thing to do is to create a conditional build where we can decide how do we
152 want to create the temporary context. For example, we can create the following
153 macros:
155 @code
156 #ifdef USE_POOL_CONTEXT
157   #define CREATE_POOL_CTX(ctx, size) talloc_pool(ctx, size)
158   #define CREATE_TMP_CTX(ctx)        talloc_new(ctx)
159 #else
160   #define CREATE_POOL_CTX(ctx, size) talloc_new(ctx)
161   #define CREATE_TMP_CTX(ctx)        talloc_new(NULL)
162 #endif
163 @endcode
165 Now if our application is under development, we will build it with macro
166 <code>USE_POOL_CONTEXT</code> undefined. This way, we  can use memory diagnostic
167 utilities to detect memory leaks.
169 The release version will be compiled with the macro defined. This will  enable
170 pool contexts and therefore reduce the <code>malloc()</code> calls, which will
171 end up in a little bit faster processing.
173 @code
174 int struct_foo_init(TALLOC_CTX *mem_ctx, struct foo **_foo)
176   int ret;
177   struct foo *foo = NULL;
178   TALLOC_CTX *tmp_ctx = CREATE_TMP_CTX(mem_ctx);
179   /* ... */
182 errno_t handle_request(TALLOC_CTX mem_ctx)
184   int ret;
185   struct foo *foo = NULL;
186   TALLOC_CTX *pool_ctx = CREATE_POOL_CTX(NULL, 1024);
187   ret = struct_foo_init(mem_ctx, &foo);
188   /* ... */
190 @endcode