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