11. Introduction 2 3The 'wmem' memory manager is Wireshark's memory management framework, replacing 4the old 'emem' framework which was removed in Wireshark 2.0. 5 6In order to make memory management easier and to reduce the probability of 7memory leaks, Wireshark provides its own memory management API. This API is 8implemented inside wsutil/wmem/ and provides memory pools and functions that make 9it easy to manage memory even in the face of exceptions (which many dissector 10functions can raise). Memory scopes for dissection are defined in epan/wmem_scopes.h. 11 12Correct use of these functions will make your code faster, and greatly reduce 13the chances that it will leak memory in exceptional cases. 14 15Wmem was originally conceived in this email to the wireshark-dev mailing list: 16https://www.wireshark.org/lists/wireshark-dev/201210/msg00178.html 17 182. Usage for Consumers 19 20If you're writing a dissector, or other "userspace" code, then using wmem 21should be very similar to using malloc or g_malloc or whatever else you're used 22to. All you need to do is include the header (epan/wmem_scopes.h) and optionally 23get a handle to a memory pool (if you want to *create* a memory pool, see the 24section "3. Usage for Producers" below). 25 26A memory pool is an opaque pointer to an object of type wmem_allocator_t, and 27it is the very first parameter passed to almost every call you make to wmem. 28Other than that parameter (and the fact that functions are prefixed wmem_) 29usage is very similar to glib and other utility libraries. For example: 30 31 wmem_alloc(myPool, 20); 32 33allocates 20 bytes in the pool pointed to by myPool. 34 352.1 Memory Pool Lifetimes 36 37Every memory pool should have a defined lifetime, or scope, after which all the 38memory in that pool is unconditionally freed. When you choose to allocate memory 39in a pool, you *must* be aware of its lifetime: if the lifetime is shorter than 40you need, your code will contain use-after-free bugs; if the lifetime is longer 41than you need, your code may contain undetectable memory leaks. In either case, 42the risks outweigh the benefits. 43 44If no pool exists whose lifetime matches the lifetime of your memory, you have 45two options: create a new pool (see section 3 of this document) or use the NULL 46pool. Any function that takes a pointer to a wmem_allocator_t can also be passed 47NULL instead, in which case the memory is managed manually (just like malloc or 48g_malloc). Memory allocated like this *must* be manually passed to wmem_free() 49in order to prevent memory leaks (however these memory leaks will at least show 50up in valgrind). Note that passing wmem_allocated memory directly to free() 51or g_free() is not safe; the backing type of manually managed memory may be 52changed without warning. 53 542.2 Wireshark Global Pools 55 56Dissectors that include the wmem_scopes.h header file will have three pools available 57to them automatically: pinfo->pool, wmem_file_scope() and 58wmem_epan_scope(); there is also a wmem_packet_scope() for cases when the 59`pinfo` argument is not accessible, but pinfo->pool should be preferred. 60 61The pinfo pool is scoped to the dissection of each packet, meaning that any 62memory allocated in it will be automatically freed at the end of the current 63packet. The file pool is similarly scoped to the dissection of each file, 64meaning that any memory allocated in it will be automatically freed when the 65current capture file is closed. 66 67NB: Using these pools outside of the appropriate scope (e.g. using the file 68 pool when there isn't a file open) will throw an assertion. 69 See the comment in epan/wmem_scopes.c for details. 70 71The epan pool is scoped to the library's lifetime - memory allocated in it is 72not freed until epan_cleanup() is called, which is typically but not necessarily 73at the very end of the program. 74 752.3 The Pinfo Pool 76 77Certain allocations (such as AT_STRINGZ address allocations and anything that 78might end up being passed to add_new_data_source) need their memory to stick 79around a little longer than the usual packet scope - basically until the 80next packet is dissected. This is, in fact, the scope of Wireshark's pinfo 81structure, so the pinfo struct has a 'pool' member which is a wmem pool scoped 82to the lifetime of the pinfo struct. 83 842.4 API 85 86Full documentation for each function (parameters, return values, behaviours) 87lives (or will live) in Doxygen-format in the header files for those functions. 88This is just an overview of which header files you should be looking at. 89 902.4.1 Core API 91 92wmem_core.h 93 - Basic memory management functions (wmem_alloc, wmem_realloc, wmem_free). 94 952.4.2 Strings 96 97wmem_strutl.h 98 - Utility functions for manipulating null-terminated C-style strings. 99 Functions like strdup and strdup_printf. 100 101wmem_strbuf.h 102 - A managed string object implementation, similar to std::string in C++ or 103 GString from Glib. 104 1052.4.3 Container Data Structures 106 107wmem_array.h 108 - A growable array (AKA vector) implementation. 109 110wmem_list.h 111 - A doubly-linked list implementation. 112 113wmem_map.h 114 - A hash map (AKA hash table) implementation. 115 116wmem_queue.h 117 - A queue implementation (first-in, first-out). 118 119wmem_stack.h 120 - A stack implementation (last-in, first-out). 121 122wmem_tree.h 123 - A balanced binary tree (red-black tree) implementation. 124 1252.4.4 Miscellaneous Utilities 126 127wmem_miscutl.h 128 - Misc. utility functions like memdup. 129 1302.5 Callbacks 131 132WARNING: You probably don't actually need these; use them only when you're 133 sure you understand the dangers. 134 135Sometimes (though hopefully rarely) it may be necessary to store data in a wmem 136pool that requires additional cleanup before it is freed. For example, perhaps 137you have a pointer to a file-handle that needs to be closed. In this case, you 138can register a callback with the wmem_register_callback function 139declared in wmem_user_cb.h. Every time the memory in a pool is freed, all 140registered cleanup functions are called first. 141 142Note that callback calling order is not defined, you cannot rely on a 143certain callback being called before or after another. 144 145WARNING: Manually freeing or moving memory (with wmem_free or wmem_realloc) 146 will NOT trigger any callbacks. It is an error to call either of 147 those functions on memory if you have a callback registered to deal 148 with the contents of that memory. 149 1503. Usage for Producers 151 152NB: If you're just writing a dissector, you probably don't need to read 153 this section. 154 155One of the problems with the old emem framework was that there were basically 156two allocator backends (glib and mmap) that were all mixed together in a mess 157of if statements, environment variables and #ifdefs. In wmem the different 158allocator backends are cleanly separated out, and it's up to the owner of the 159pool to pick one. 160 1613.1 Available Allocator Back-Ends 162 163Each available allocator type has a corresponding entry in the 164wmem_allocator_type_t enumeration defined in wmem_core.h. See the doxygen 165comments in that header file for details on each type. 166 1673.2 Creating a Pool 168 169To create a pool, include the regular wmem header and call the 170wmem_allocator_new() function with the appropriate type value. 171For example: 172 173 #include <wsutil/wmem/wmem.h> 174 175 wmem_allocator_t *myPool; 176 myPool = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE); 177 178From here on in, you don't need to remember which type of allocator you used 179(although allocator authors are welcome to expose additional allocator-specific 180helper functions in their headers). The "myPool" variable can be passed around 181and used as normal in allocation requests as described in section 2 of this 182document. 183 1843.3 Destroying a Pool 185 186Regardless of which allocator you used to create a pool, it can be destroyed 187with a call to the function wmem_destroy_allocator(). For example: 188 189 #include <wsutil/wmem/wmem.h> 190 191 wmem_allocator_t *myPool; 192 193 myPool = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE); 194 195 /* Allocate some memory in myPool ... */ 196 197 wmem_destroy_allocator(myPool); 198 199Destroying a pool will free all the memory allocated in it. 200 2013.4 Reusing a Pool 202 203It is possible to free all the memory in a pool without destroying it, 204allowing it to be reused later. Depending on the type of allocator, doing this 205(by calling wmem_free_all()) can be significantly cheaper than fully destroying 206and recreating the pool. This method is therefore recommended, especially when 207the pool would otherwise be scoped to a single iteration of a loop. For example: 208 209 #include <wsutil/wmem/wmem.h> 210 211 wmem_allocator_t *myPool; 212 213 myPool = wmem_allocator_new(WMEM_ALLOCATOR_SIMPLE); 214 for (...) { 215 216 /* Allocate some memory in myPool ... */ 217 218 /* Free the memory, faster than destroying and recreating 219 the pool each time through the loop. */ 220 wmem_free_all(myPool); 221 } 222 wmem_destroy_allocator(myPool); 223 2244. Internal Design 225 226Despite being written in Wireshark's standard C90, wmem follows a fairly 227object-oriented design pattern. Although efficiency is always a concern, the 228primary goals in writing wmem were maintainability and preventing memory 229leaks. 230 2314.1 struct _wmem_allocator_t 232 233The heart of wmem is the _wmem_allocator_t structure defined in the 234wmem_allocator.h header file. This structure uses C function pointers to 235implement a common object-oriented design pattern known as an interface (also 236known as an abstract class to those who are more familiar with C++). 237 238Different allocator implementations can provide exactly the same interface by 239assigning their own functions to the members of an instance of the structure. 240The structure has eight members in three groups. 241 2424.1.1 Implementation Details 243 244 - private_data 245 - type 246 247The private_data pointer is a void pointer that the allocator implementation can 248use to store whatever internal structures it needs. A pointer to private_data is 249passed to almost all of the other functions that the allocator implementation 250must define. 251 252The type field is an enumeration of type wmem_allocator_type_t (see 253section 3.1). Its value is set by the wmem_allocator_new() function, not 254by the implementation-specific constructor. This field should be considered 255read-only by the allocator implementation. 256 2574.1.2 Consumer Functions 258 259 - walloc() 260 - wfree() 261 - wrealloc() 262 263These function pointers should be set to functions with semantics obviously 264similar to their standard-library namesakes. Each one takes an extra parameter 265that is a copy of the allocator's private_data pointer. 266 267Note that wrealloc() and wfree() are not expected to be called directly by user 268code in most cases - they are primarily optimizations for use by data 269structures that wmem might want to implement (it's inefficient, for example, to 270implement a dynamically sized array without some form of realloc). 271 272Also note that allocators do not have to handle NULL pointers or 0-length 273requests in any way - those checks are done in an allocator-agnostic way 274higher up in wmem. Allocator authors can assume that all incoming pointers 275(to wrealloc and wfree) are non-NULL, and that all incoming lengths (to walloc 276and wrealloc) are non-0. 277 2784.1.3 Producer/Manager Functions 279 280 - free_all() 281 - gc() 282 - cleanup() 283 284All of these functions take only one parameter, which is the allocator's 285private_data pointer. 286 287The free_all() function should free all the memory currently allocated in the 288pool. Note that this is not necessarily exactly the same as calling free() 289on all the allocated blocks - free_all() is allowed to do additional cleanup 290or to make use of optimizations not available when freeing one block at a time. 291 292The gc() function should do whatever it can to reduce excess memory usage in 293the dissector by returning unused blocks to the OS, optimizing internal data 294structures, etc. 295 296The cleanup() function should do any final cleanup and free any and all memory. 297It is basically the equivalent of a destructor function. For simplicity, wmem 298is guaranteed to call free_all() immediately before calling this function. There 299is no such guarantee that gc() has (ever) been called. 300 3014.2 Pool-Agnostic API 302 303One of the issues with emem was that the API (including the public data 304structures) required wrapper functions for each scope implemented. Even 305if there was a stack implementation in emem, it wasn't necessarily available 306for use with file-scope memory unless someone took the time to write se_stack_ 307wrapper functions for the interface. 308 309In wmem, all public APIs take the pool as the first argument, so that they can 310be written once and used with any available memory pool. Data structures like 311wmem's stack implementation only take the pool when created - the provided 312pointer is stored internally with the data structure, and subsequent calls 313(like push and pop) will take the stack itself instead of the pool. 314 3154.3 Debugging 316 317The primary debugging control for wmem is the WIRESHARK_DEBUG_WMEM_OVERRIDE 318environment variable. If set, this value forces all calls to 319wmem_allocator_new() to return the same type of allocator, regardless of which 320type is requested normally by the code. It currently has three valid values: 321 322 - The value "simple" forces the use of WMEM_ALLOCATOR_SIMPLE. The valgrind 323 script currently sets this value, since the simple allocator is the only 324 one whose memory allocations are trackable properly by valgrind. 325 326 - The value "strict" forces the use of WMEM_ALLOCATOR_STRICT. The fuzz-test 327 script currently sets this value, since the goal when fuzz-testing is to find 328 as many errors as possible. 329 330 - The value "block" forces the use of WMEM_ALLOCATOR_BLOCK. This is not 331 currently used by any scripts, but is useful for stress-testing the block 332 allocator. 333 334 - The value "block_fast" forces the use of WMEM_ALLOCATOR_BLOCK_FAST. This is 335 not currently used by any scripts, but is useful for stress-testing the fast 336 block allocator. 337 338Note that regardless of the value of this variable, it will always be safe to 339call allocator-specific helpers functions. They are required to be safe no-ops 340if the allocator argument is of the wrong type. 341 3424.4 Testing 343 344There is a simple test suite for wmem that lives in the file wmem_test.c and 345should get automatically built into the binary 'wmem_test' when building 346Wireshark. It contains at least basic tests for all existing functionality. 347The suite is run automatically by the build-bots via the shell script 348test/test.py which calls out to test/suite_unittests.py. 349 350New features added to wmem (allocators, data structures, utility 351functions, etc.) MUST also have tests added to this suite. 352 353The test suite could potentially use a clean-up by someone more 354intimately familiar with Glib's testing framework, but it does the job. 355 3565. A Note on Performance 357 358Because of my own bad judgment, there is the persistent idea floating around 359that wmem is somehow magically faster than other allocators in the general case. 360This is false. 361 362First, wmem supports multiple different allocator backends (see sections 3 and 4 363of this document), so it is confusing and misleading to try and compare the 364performance of "wmem" in general with another system anyways. 365 366Second, any modern system-provided malloc already has a very clever and 367efficient allocator algorithm that makes use of blocks, arenas and all sorts of 368other fancy tricks. Trying to be faster than libc's allocator is generally a 369waste of time unless you have a specific allocation pattern to optimize for. 370 371Third, while there were historically arguments to be made for putting something 372in front of the kernel to reduce the number of context-switches, modern libc 373implementations should already do that. Making a dynamic library call is still 374marginally more expensive than calling a locally-defined linker-optimized 375function, but it's a difference too small to care about. 376 377With all that said, it is true that *some* of wmem's allocators can be 378substantially faster than your standard libc malloc, in *some* use cases: 379 - The BLOCK and BLOCK_FAST allocators both provide very efficient free_all 380 operations, which can be many orders of magnitude faster than calling free() 381 on each individual allocation. 382 - The BLOCK_FAST allocator in particular is optimized for Wireshark's packet 383 scope pool. It has an extremely short, well-defined lifetime, and a very 384 regular pattern of allocations; I was able to use that knowledge to beat libc 385 rather handily, *in that specific use case*. 386 387/* 388 * Editor modelines - https://www.wireshark.org/tools/modelines.html 389 * 390 * Local variables: 391 * c-basic-offset: 4 392 * tab-width: 8 393 * indent-tabs-mode: nil 394 * End: 395 * 396 * vi: set shiftwidth=4 tabstop=8 expandtab: 397 * :indentSize=4:tabSize=8:noTabs=true: 398 */ 399