]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cbdata.h
Fix some cbdataFree related memory leaks
[thirdparty/squid.git] / src / cbdata.h
1 /*
2 * Copyright (C) 1996-2015 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #ifndef SQUID_CBDATA_H
10 #define SQUID_CBDATA_H
11
12 #include "typedefs.h"
13
14 /**
15 \defgroup CBDATAAPI Callback Data Allocator API
16 \ingroup Components
17 \par
18 * Squid's extensive use of callback functions makes it very
19 * susceptible to memory access errors. To address this all callback
20 * functions make use of a construct called cbdata. This allows
21 * functions doing callbacks to verify that the caller is still
22 * valid before making the callback.
23 *
24 \note cbdata is intended for callback data and is tailored specifically
25 * to make callbacks less dangerous leaving as few windows of errors as
26 * possible. It is not suitable or intended as a generic RefCount
27 * memory allocator.
28 *
29 *
30 \section Examples Examples
31 \par
32 * Here you can find some examples on how to use cbdata, and why.
33 *
34 \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed
35 \par
36 * For a asyncronous operation with callback functions, the normal
37 * sequence of events in programs NOT using cbdata is as follows:
38 *
39 \code
40 // initialization
41 type_of_data our_data;
42 ...
43 our_data = malloc(...);
44 ...
45 // Initiate a asyncronous operation, with our_data as callback_data
46 fooOperationStart(bar, callback_func, our_data);
47 ...
48 // The asyncronous operation completes and makes the callback
49 callback_func(callback_data, ....);
50 // Some time later we clean up our data
51 free(our_data);
52 \endcode
53 *
54 \par
55 * However, things become more interesting if we want or need
56 * to free the callback_data, or otherwise cancel the callback,
57 * before the operation completes. In constructs like this you
58 * can quite easily end up with having the memory referenced
59 * pointed to by callback_data freed before the callback is invoked
60 * causing a program failure or memory corruption:
61 *
62 \code
63 // initialization
64 type_of_data our_data;
65 ...
66 our_data = malloc(...);
67 ...
68 // Initiate a asyncronous operation, with our_data as callback_data
69 fooOperationStart(bar, callback_func, our_data);
70 ...
71 // ouch, something bad happened elsewhere.. try to cleanup
72 // but the programmer forgot there is a callback pending from
73 // fooOperationsStart() (an easy thing to forget when writing code
74 // to deal with errors, especially if there may be many different
75 // pending operation)
76 free(our_data);
77 ...
78 // The asyncronous operation completes and makes the callback
79 callback_func(callback_data, ....);
80 // CRASH, the memory pointer to by callback_data is no longer valid
81 // at the time of the callback
82 \endcode
83 *
84 \subsection AsyncOpWithCBDATA Asyncronous operation with cbdata
85 *
86 \par
87 * The callback data allocator lets us do this in a uniform and
88 * safe manner. The callback data allocator is used to allocate,
89 * track and free memory pool objects used during callback
90 * operations. Allocated memory is locked while the asyncronous
91 * operation executes elsewhere, and is freed when the operation
92 * completes. The normal sequence of events is:
93 *
94 \code
95 // initialization
96 type_of_data our_data;
97 ...
98 our_data = cbdataAlloc(type_of_data);
99 ...
100 // Initiate a asyncronous operation, with our_data as callback_data
101 fooOperationStart(..., callback_func, our_data);
102 ...
103 // foo
104 void *local_pointer = cbdataReference(callback_data);
105 ....
106 // The asyncronous operation completes and makes the callback
107 void *cbdata;
108 if (cbdataReferenceValidDone(local_pointer, &cbdata))
109 callback_func(...., cbdata);
110 ...
111 cbdataFree(our_data);
112 \endcode
113 *
114 \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata
115 *
116 \par
117 * With this scheme, nothing bad happens if cbdataFree() gets called
118 * before fooOperantionComplete(...).
119 *
120 \par Initalization
121 \code
122 type_of_data our_data;
123 ...
124 our_data = cbdataAlloc(type_of_data);
125 \endcode
126 * Initiate a asyncronous operation, with our_data as callback_data
127 \code
128 fooOperationStart(..., callback_func, our_data);
129 \endcode
130 * do some stuff with it
131 \code
132 void *local_pointer = cbdataReference(callback_data);
133 \endcode
134 * something bad happened elsewhere.. cleanup
135 \code
136 cbdataFree(our_data);
137 \endcode
138 * The asyncronous operation completes and tries to make the callback
139 \code
140 void *cbdata;
141 if (cbdataReferenceValidDone(local_pointer, &cbdata))
142 {
143 \endcode
144 * won't be called, as the data is no longer valid
145 \code
146 callback_func(...., cbdata);
147 }
148 \endcode
149 *
150 \par
151 * In this case, when cbdataFree() is called before
152 * cbdataReferenceValidDone(), the callback_data gets marked as invalid.
153 * When the callback_data is invalid before executing the callback
154 * function, cbdataReferenceValidDone() will return 0 and
155 * callback_func is never executed.
156 *
157 \subsection AddingCBDATAType Adding a new cbdata registered type
158 *
159 \par
160 * To add new module specific data types to the allocator one uses the
161 * macro CBDATA_CLASS() in the class private section, and CBDATA_CLASS_INIT()
162 * or CBDATA_NAMESPACED_CLASS_INIT() in the .cc file.
163 * This creates new(), delete() and toCbdata() methods
164 * definition in class scope. Any allocate calls must be made with
165 * new() and destruction with delete(), they may be called from anywhere.
166 */
167
168 /**
169 *\ingroup CBDATAAPI
170 * cbdata types. Similar to the MEM_* types, but managed in cbdata.cc
171 * A big difference is that cbdata types are dynamically allocated.
172 * Initially only UNKNOWN type is predefined. Other types are added runtime.
173 */
174 typedef int cbdata_type;
175 static const cbdata_type CBDATA_UNKNOWN = 0;
176
177 /// \ingroup CBDATAAPI
178 void cbdataRegisterWithCacheManager(void);
179
180 /**
181 * Allocates a new entry of a registered CBDATA type.
182 * \deprecated use CBDATA_CLASS() instead
183 */
184 void *cbdataInternalAlloc(cbdata_type type, const char *, int);
185 /// \deprecated use CBDATA_CLASS() instead
186 #define cbdataAlloc(type) ((type *)cbdataInternalAlloc(CBDATA_##type,__FILE__,__LINE__))
187
188 /**
189 * Frees a entry allocated by cbdataAlloc().
190 *
191 \note If there are active references to the entry then the entry
192 * will be freed with the last reference is removed. However,
193 * cbdataReferenceValid() will return false for those references.
194 * \deprecated use CBDATA_CLASS() instead
195 */
196 void *cbdataInternalFree(void *p, const char *, int);
197 /// \deprecated use CBDATA_CLASS() instead
198 #define cbdataFree(var) do {if (var) {cbdataInternalFree(var,__FILE__,__LINE__); var = NULL;}} while(0)
199
200 #if USE_CBDATA_DEBUG
201 void cbdataInternalLockDbg(const void *p, const char *, int);
202 #define cbdataInternalLock(a) cbdataInternalLockDbg(a,__FILE__,__LINE__)
203
204 void cbdataInternalUnlockDbg(const void *p, const char *, int);
205 #define cbdataInternalUnlock(a) cbdataInternalUnlockDbg(a,__FILE__,__LINE__)
206
207 int cbdataInternalReferenceDoneValidDbg(void **p, void **tp, const char *, int);
208 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValidDbg((void **)&(var), (ptr), __FILE__,__LINE__)
209
210 #else
211 void cbdataInternalLock(const void *p);
212 void cbdataInternalUnlock(const void *p);
213
214 /**
215 * Removes a reference created by cbdataReference() and checks
216 * it for validity. Meant to be used on the last dereference,
217 * usually to make a callback.
218 *
219 \code
220 void *cbdata;
221 ...
222 if (cbdataReferenceValidDone(reference, &cbdata)) != NULL)
223 callback(..., cbdata);
224 \endcode
225 *
226 \param var The reference variable. Will be automatically cleared to NULL.
227 \param ptr A temporary pointer to the referenced data (if valid).
228 */
229 int cbdataInternalReferenceDoneValid(void **p, void **tp);
230 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
231
232 #endif /* !CBDATA_DEBUG */
233
234 /**
235 * \param p A cbdata entry reference pointer.
236 *
237 * \retval 0 A reference is stale. The pointer refers to a entry freed by cbdataFree().
238 * \retval true The reference is valid and active.
239 */
240 int cbdataReferenceValid(const void *p);
241
242 /// \ingroup CBDATAAPI
243 cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size, FREE * free_func);
244
245 /**
246 * This needs to be defined FIRST in the class definition.
247 * It plays with private/public states in C++.
248 */
249 #define CBDATA_CLASS(type) \
250 public: \
251 void *operator new(size_t size) { \
252 assert(size == sizeof(type)); \
253 if (!CBDATA_##type) \
254 CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), NULL); \
255 return (type *)cbdataInternalAlloc(CBDATA_##type,__FILE__,__LINE__); \
256 } \
257 void operator delete (void *address) { \
258 if (address) cbdataInternalFree(address,__FILE__,__LINE__);\
259 } \
260 void *toCbdata() { return this; } \
261 private: \
262 static cbdata_type CBDATA_##type;
263
264 /**
265 \par
266 * Creates a new reference to a cbdata entry. Used when you need to
267 * store a reference in another structure. The reference can later
268 * be verified for validity by cbdataReferenceValid().
269 *
270 \param var
271 * The reference variable is a pointer to the entry, in all
272 * aspects identical to the original pointer. But semantically it
273 * is quite different. It is best if the reference is thought of
274 * and handled as a "void *".
275 */
276 #define cbdataReference(var) (cbdataInternalLock(var), var)
277
278 /**
279 \ingroup CBDATAAPI
280 * Removes a reference created by cbdataReference().
281 *
282 \param var The reference variable. Will be automatically cleared to NULL.
283 */
284 #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
285
286 /// \ingroup CBDATAAPI
287 #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
288 #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
289
290 /**
291 * Macro that defines a new cbdata datatype. Similar to a variable
292 * or struct definition. Scope is always local to the file/block
293 * where it is defined and all calls to cbdataAlloc() for this type
294 * must be within the same scope as the CBDATA_TYPE declaration.
295 * Allocated entries may be referenced or freed anywhere with no
296 * restrictions on scope.
297 * \deprecated Use CBDATA_CLASS() instead
298 */
299 #define CBDATA_TYPE(type) static cbdata_type CBDATA_##type = CBDATA_UNKNOWN
300
301 /**
302 \ingroup CBDATAAPI
303 *
304 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
305 *
306 \par
307 * Alternative to CBDATA_INIT_TYPE()
308 *
309 \param type Type being initialized
310 \param free_func The freehandler called when the last known reference to an allocated entry goes away.
311 */
312 #define CBDATA_INIT_TYPE_FREECB(type, free_func) do { if (!CBDATA_##type) CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type), free_func); } while (false)
313
314 /**
315 * Initializes the cbdatatype. Must be called prior to the first use of cbdataAlloc() for the type.
316 *
317 \par
318 * Alternative to CBDATA_INIT_TYPE_FREECB()
319 *
320 \param type Type being initialized
321 *
322 * \deprecated Use CBDATA_CLASS() instead
323 */
324 #define CBDATA_INIT_TYPE(type) CBDATA_INIT_TYPE_FREECB(type, NULL)
325
326 /**
327 \ingroup CBDATA
328 *
329 * A generic wrapper for passing objects through cbdata.
330 * Use this when you need to pass callback data to a blocking
331 * operation, but you don't want to/cannot have that pointer be cbdata itself.
332 */
333 class generic_cbdata
334 {
335 CBDATA_CLASS(generic_cbdata);
336
337 public:
338
339 generic_cbdata(void * aData) : data(aData) {}
340
341 template<typename wrapped_type>void unwrap(wrapped_type **output) {
342 *output = static_cast<wrapped_type *>(data);
343 delete this;
344 }
345
346 private:
347 /**
348 * The wrapped data - only public to allow the mild abuse of this facility
349 * done by store_swapout - it gives a wrapped StoreEntry to StoreIO as the
350 * object to be given to the callbacks. That needs to be fully cleaned up!
351 * - RBC 20060820
352 \todo CODE: make this a private field.
353 */
354 void *data; /* the wrapped data */
355 };
356
357 #endif /* SQUID_CBDATA_H */
358