1 /*
2  * Copyright (C) 1996-2021 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_SRC_CBDATA_H
10 #define SQUID_SRC_CBDATA_H
11 
12 /**
13 \page CBDATA Callback Data Allocator API
14 
15  \section  Introduction
16 
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  \par
30    The AsyncJob/AsyncCall mechanism is preferred over CBDATA.
31    It replaces cbdata with an AsyncCall::Pointer object which
32    performs the same memory protection duties via other means.
33 
34  \section Examples Examples
35  \par
36    Here you can find some examples on how to use cbdata, and why.
37 
38  \subsection AsyncOpWithoutCBDATA Asynchronous operation without cbdata, showing why cbdata is needed
39  \par
40    For a asyncronous operation with callback functions, the normal
41    sequence of events in programs NOT using cbdata is as follows:
42 
43  \code
44     // initialization
45     type_of_data our_data = new ...;
46     ...
47     // Initiate a asyncronous operation, with our_data as callback_data
48     fooOperationStart(bar, callback_func, our_data);
49     ...
50     // The asyncronous operation completes and makes the callback
51     callback_func(callback_data, ....);
52     // Some time later we clean up our data
53     delete our_data;
54  \endcode
55 
56  \par
57    However, things become more interesting if we want or need
58    to free the callback_data, or otherwise cancel the callback,
59    before the operation completes. In constructs like this you
60    can quite easily end up with having the memory referenced
61    pointed to by callback_data freed before the callback is invoked
62    causing a program failure or memory corruption:
63 
64  \code
65     // initialization
66     type_of_data our_data = new ...;
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 operations.
76     delete 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 = new type_of_data;
97     ...
98     // Initiate a asyncronous operation, with our_data as callback_data
99     fooOperationStart(..., callback_func, our_data);
100     ...
101     // foo
102     void *local_pointer = cbdataReference(callback_data);
103     ....
104     // The asyncronous operation completes and makes the callback
105     void *cbdata;
106     if (cbdataReferenceValidDone(local_pointer, &cbdata))
107         callback_func(...., cbdata);
108     delete our_data;
109  \endcode
110 
111  \subsection AsynchronousOpCancelledByCBDATA Asynchronous operation cancelled by cbdata
112 
113  \par
114    With this scheme, nothing bad happens if delete gets called
115    before fooOperantionComplete(...).
116 
117  \par   Initalization
118  \code
119     // initialization
120     type_of_data our_data = new type_of_data;
121     ...
122     // Initiate a asyncronous operation, with our_data as callback_data
123     fooOperationStart(..., callback_func, our_data);
124     ...
125     // do some stuff with it
126     void *local_pointer = cbdataReference(callback_data);
127     ...
128     // something bad happened elsewhere.. cleanup
129     delete our_data;
130     ....
131     // The asyncronous operation completes and makes the callback
132     void *cbdata;
133     if (cbdataReferenceValidDone(local_pointer, &cbdata))
134         // won't be called, as the data is no longer valid
135         callback_func(...., cbdata);
136     delete our_data;
137  \endcode
138 
139  \par
140    In this case, when delete is called before cbdataReferenceValidDone(),
141    the callback_data gets marked as invalid.
142    When the callback_data is invalid before executing the callback
143    function, cbdataReferenceValidDone() will return 0 and
144    callback_func is never executed.
145 
146  \subsection AddingCBDATAType Adding a new cbdata registered type
147 
148  \par
149    To add new module specific data types to the allocator one uses
150    the macro CBDATA_CLASS() in the class private section, and
151    CBDATA_CLASS_INIT() or CBDATA_NAMESPACED_CLASS_INIT() in the
152    class .cc file.
153 
154  \code
155     class Foo
156     {
157         CBDATA_CLASS(Foo);
158 
159     public:
160         Foo() {}
161         ~Foo() {}
162     };
163     ...
164     CBDATA_CLASS_INIT(Foo);
165  \endcode
166 
167  \par
168    These macros create new(), delete() and toCbdata() methods
169    definition in class scope. Any allocate calls must be made with
170    new() and destruction with delete(), they may be called from
171    anywhere.
172 
173  \par
174    The class constructor must make sure that all member
175    variables are initialized, and the class destructor that all
176    dynamic memory is released.
177 
178  \par
179    The CbcPointer<> template should be used to create a smart-pointer
180    type for simple reference tracking. It provides get() and valid()
181    accessors for use instead of cbdataReferenceValid(), and performs
182    reliable automatic cbdataReference() and cbdataReferenceDone()
183    tracking.
184    Note that it does NOT provide a replacement for cbdataReferenceValidDone().
185 
186  */
187 
188 /**
189  * cbdata types. Similar to the MEM_* types, but managed in cbdata.cc
190  * A big difference is that cbdata types are dynamically allocated.
191  *
192  * Initially only UNKNOWN type is predefined.
193  * Other types are added at runtime by CBDATA_CLASS().
194  */
195 typedef int cbdata_type;
196 static const cbdata_type CBDATA_UNKNOWN = 0;
197 
198 /**
199  * Create a run-time registration of CBDATA component with
200  * the Squid cachemgr
201  */
202 void cbdataRegisterWithCacheManager(void);
203 
204 /**
205  * Allocates a new entry of a registered CBDATA type.
206  *
207  * \note For internal CBDATA use only.
208  */
209 void *cbdataInternalAlloc(cbdata_type type, const char *, int);
210 
211 /**
212  * Frees a entry allocated by cbdataInternalAlloc().
213  *
214  * Once this has been called cbdataReferenceValid() and
215  * cbdataReferenceValidDone() will return false regardless
216  * of whether there are remaining cbdata references.
217  *
218  * cbdataReferenceDone() must still be called for any active
219  * references to the cbdata entry. The cbdata entry will be freed
220  * only when the last reference is removed.
221  *
222  * \note For internal CBDATA use only.
223  */
224 void *cbdataInternalFree(void *p, const char *, int);
225 
226 #if USE_CBDATA_DEBUG
227 void cbdataInternalLockDbg(const void *p, const char *, int);
228 #define cbdataInternalLock(a) cbdataInternalLockDbg(a,__FILE__,__LINE__)
229 
230 void cbdataInternalUnlockDbg(const void *p, const char *, int);
231 #define cbdataInternalUnlock(a) cbdataInternalUnlockDbg(a,__FILE__,__LINE__)
232 
233 int cbdataInternalReferenceDoneValidDbg(void **p, void **tp, const char *, int);
234 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValidDbg((void **)&(var), (ptr), __FILE__,__LINE__)
235 
236 #else
237 void cbdataInternalLock(const void *p);
238 void cbdataInternalUnlock(const void *p);
239 
240 /**
241  * Removes a reference created by cbdataReference() and checks
242  * it for validity. Meant to be used on the last dereference,
243  * usually to make a callback.
244  *
245  \code
246         void *cbdata;
247         ...
248         if (cbdataReferenceValidDone(reference, &cbdata)) != NULL)
249             callback(..., cbdata);
250  \endcode
251  *
252  * \param var The reference variable. Will be automatically cleared to NULL.
253  * \param ptr A temporary pointer to the referenced data (if valid).
254  */
255 int cbdataInternalReferenceDoneValid(void **p, void **tp);
256 #define cbdataReferenceValidDone(var, ptr) cbdataInternalReferenceDoneValid((void **)&(var), (ptr))
257 
258 #endif /* !CBDATA_DEBUG */
259 
260 /**
261  * \param p A cbdata entry reference pointer.
262  *
263  * \retval 0    A reference is stale. The pointer refers to a entry already freed.
264  * \retval true The reference is valid and active.
265  */
266 int cbdataReferenceValid(const void *p);
267 
268 /**
269  * Create a run-time registration for the class type with cbdata memory allocator.
270  *
271  * \note For internal CBDATA use only.
272  */
273 cbdata_type cbdataInternalAddType(cbdata_type type, const char *label, int size);
274 
275 /// declaration-generator used internally by CBDATA_CLASS() and CBDATA_CHILD()
276 #define CBDATA_DECL_(type, methodSpecifiers) \
277     public: \
278         void *operator new(size_t size) { \
279           assert(size == sizeof(type)); \
280           if (!CBDATA_##type) CBDATA_##type = cbdataInternalAddType(CBDATA_##type, #type, sizeof(type)); \
281           return (type *)cbdataInternalAlloc(CBDATA_##type,__FILE__,__LINE__); \
282         } \
283         void operator delete (void *address) { \
284           if (address) cbdataInternalFree(address,__FILE__,__LINE__); \
285         } \
286         void *toCbdata() methodSpecifiers { return this; } \
287     private: \
288        static cbdata_type CBDATA_##type;
289 
290 /// Starts cbdata-protection in a class hierarchy.
291 /// Child classes in the same hierarchy should use CBDATA_CHILD().
292 class CbdataParent
293 {
294 public:
~CbdataParent()295     virtual ~CbdataParent() {}
296     virtual void *toCbdata() = 0;
297 };
298 
299 /// cbdata-enables a stand-alone class that is not a CbdataParent child
300 /// sets the class declaration section to "private"
301 /// use this at the start of your class declaration for consistency sake
302 #define CBDATA_CLASS(type) CBDATA_DECL_(type, noexcept)
303 
304 /// cbdata-enables a CbdataParent child class (including grandchildren)
305 /// sets the class declaration section to "private"
306 /// use this at the start of your class declaration for consistency sake
307 #define CBDATA_CHILD(type) CBDATA_DECL_(type, override final)
308 
309 /**
310  * Creates a global instance pointer for the CBDATA memory allocator
311  * to allocate and free objects for the matching CBDATA_CLASS().
312  *
313  * Place this in the appropriate .cc file for the class being registered.
314  *
315  * May be placed inside an explicit namespace scope declaration,
316  * or CBDATA_NAMESPACED_CLASS_INIT() used instead.
317  */
318 #define CBDATA_CLASS_INIT(type) cbdata_type type::CBDATA_##type = CBDATA_UNKNOWN
319 
320 /**
321  * Creates a global instance pointer for the CBDATA memory allocator
322  * to allocate and free objects for the matching CBDATA_CLASS().
323  *
324  * Place this in the appropriate .cc file for the class being registered.
325  */
326 #define CBDATA_NAMESPACED_CLASS_INIT(namespace, type) cbdata_type namespace::type::CBDATA_##type = CBDATA_UNKNOWN
327 
328 /**
329  * Creates a new reference to a cbdata entry. Used when you need to
330  * store a reference in another structure. The reference can later
331  * be verified for validity by cbdataReferenceValid().
332  *
333  * \deprecated Prefer the use of CbcPointer<> smart pointer.
334  *
335  * \param var
336  *       The reference variable is a pointer to the entry, in all
337  *       aspects identical to the original pointer. But semantically it
338  *       is quite different. It is best if the reference is thought of
339  *       and handled as a "void *".
340  */
341 #define cbdataReference(var)    (cbdataInternalLock(var), var)
342 
343 /**
344  * Removes a reference created by cbdataReference().
345  *
346  * \deprecated Prefer the use of CbcPointer<> smart pointer.
347  *
348  * \param var The reference variable. Will be automatically cleared to NULL.
349  */
350 #define cbdataReferenceDone(var) do {if (var) {cbdataInternalUnlock(var); var = NULL;}} while(0)
351 
352 /**
353  * A generic wrapper for passing object pointers through cbdata.
354  * Use this when you need to pass callback data to a blocking
355  * operation, but you don't want to/cannot have that pointer be
356  * cbdata itself.
357  */
358 class generic_cbdata
359 {
360     CBDATA_CLASS(generic_cbdata);
361 
362 public:
generic_cbdata(void * aData)363     generic_cbdata(void *aData) : data(aData) {}
364 
unwrap(wrapped_type ** output)365     template<typename wrapped_type>void unwrap(wrapped_type **output) {
366         *output = static_cast<wrapped_type *>(data);
367         delete this;
368     }
369 
370 private:
371     void *data;
372 };
373 
374 // Discouraged: Use CbcPointer<> and asynchronous calls instead if possible.
375 /// an old-style void* callback parameter
376 class CallbackData
377 {
378 public:
CallbackData()379     CallbackData(): data_(nullptr) {}
CallbackData(void * data)380     CallbackData(void *data): data_(cbdataReference(data)) {}
CallbackData(const CallbackData & other)381     CallbackData(const CallbackData &other): data_(cbdataReference(other.data_)) {}
CallbackData(CallbackData && other)382     CallbackData(CallbackData &&other): data_(other.data_) { other.data_ = nullptr; }
~CallbackData()383     ~CallbackData() { cbdataReferenceDone(data_); }
384 
385     // implement if needed
386     CallbackData &operator =(const CallbackData &other) = delete;
387 
validDone()388     void *validDone() { void *result; return cbdataReferenceValidDone(data_, &result) ? result : nullptr; }
389 
390 private:
391     void *data_; ///< raw callback data, maybe invalid
392 };
393 
394 #endif /* SQUID_CBDATA_H */
395 
396