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