1 /*
2  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3  *
4  * This Source Code Form is subject to the terms of the Mozilla Public
5  * License, v. 2.0. If a copy of the MPL was not distributed with this
6  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7  *
8  * See the COPYRIGHT file distributed with this work for additional
9  * information regarding copyright ownership.
10  */
11 
12 #ifndef ISC_MEM_H
13 #define ISC_MEM_H 1
14 
15 /*! \file isc/mem.h */
16 
17 #include <stdbool.h>
18 #include <stdio.h>
19 
20 #include <isc/attributes.h>
21 #include <isc/lang.h>
22 #include <isc/mutex.h>
23 #include <isc/types.h>
24 
25 ISC_LANG_BEGINDECLS
26 
27 #define ISC_MEM_LOWATER 0
28 #define ISC_MEM_HIWATER 1
29 typedef void (*isc_mem_water_t)(void *, int);
30 
31 /*%
32  * Define ISC_MEM_TRACKLINES=1 to turn on detailed tracing of memory
33  * allocation and freeing by file and line number.
34  */
35 #ifndef ISC_MEM_TRACKLINES
36 #define ISC_MEM_TRACKLINES 0
37 #endif /* ifndef ISC_MEM_TRACKLINES */
38 
39 extern unsigned int isc_mem_debugging;
40 extern unsigned int isc_mem_defaultflags;
41 
42 /*@{*/
43 #define ISC_MEM_DEBUGTRACE  0x00000001U
44 #define ISC_MEM_DEBUGRECORD 0x00000002U
45 #define ISC_MEM_DEBUGUSAGE  0x00000004U
46 #define ISC_MEM_DEBUGALL    0x0000001FU
47 /*!<
48  * The variable isc_mem_debugging holds a set of flags for
49  * turning certain memory debugging options on or off at
50  * runtime.  It is initialized to the value ISC_MEM_DEGBUGGING,
51  * which is 0 by default but may be overridden at compile time.
52  * The following flags can be specified:
53  *
54  * \li #ISC_MEM_DEBUGTRACE
55  *	Log each allocation and free to isc_lctx.
56  *
57  * \li #ISC_MEM_DEBUGRECORD
58  *	Remember each allocation, and match them up on free.
59  *	Crash if a free doesn't match an allocation.
60  *
61  * \li #ISC_MEM_DEBUGUSAGE
62  *	If a hi_water mark is set, print the maximum inuse memory
63  *	every time it is raised once it exceeds the hi_water mark.
64  */
65 /*@}*/
66 
67 #if ISC_MEM_TRACKLINES
68 #define _ISC_MEM_FILELINE , __FILE__, __LINE__
69 #define _ISC_MEM_FLARG	  , const char *, unsigned int
70 #else /* if ISC_MEM_TRACKLINES */
71 #define _ISC_MEM_FILELINE
72 #define _ISC_MEM_FLARG
73 #endif /* if ISC_MEM_TRACKLINES */
74 
75 /*
76  * Flags for isc_mem_create() calls.
77  */
78 #define ISC_MEMFLAG_RESERVED1 0x00000001 /* reserved, obsoleted, don't use */
79 #define ISC_MEMFLAG_RESERVED2 0x00000002 /* reserved, obsoleted, don't use */
80 #define ISC_MEMFLAG_FILL \
81 	0x00000004 /* fill with pattern after alloc and frees */
82 
83 /*%
84  * Define ISC_MEM_DEFAULTFILL=1 to turn filling the memory with pattern
85  * after alloc and free.
86  */
87 #if ISC_MEM_DEFAULTFILL
88 #define ISC_MEMFLAG_DEFAULT ISC_MEMFLAG_FILL
89 #else /* if !ISC_MEM_USE_INTERNAL_MALLOC */
90 #define ISC_MEMFLAG_DEFAULT 0
91 #endif /* if !ISC_MEM_USE_INTERNAL_MALLOC */
92 
93 /*%
94  * isc_mem_putanddetach() is a convenience function for use where you
95  * have a structure with an attached memory context.
96  *
97  * Given:
98  *
99  * \code
100  * struct {
101  *	...
102  *	isc_mem_t *mctx;
103  *	...
104  * } *ptr;
105  *
106  * isc_mem_t *mctx;
107  *
108  * isc_mem_putanddetach(&ptr->mctx, ptr, sizeof(*ptr));
109  * \endcode
110  *
111  * is the equivalent of:
112  *
113  * \code
114  * mctx = NULL;
115  * isc_mem_attach(ptr->mctx, &mctx);
116  * isc_mem_detach(&ptr->mctx);
117  * isc_mem_put(mctx, ptr, sizeof(*ptr));
118  * isc_mem_detach(&mctx);
119  * \endcode
120  */
121 
122 /*%
123  * These functions are actually implemented in isc__mem_<function>
124  * (two underscores). The single-underscore macros are used to pass
125  * __FILE__ and __LINE__, and in the case of the put functions, to
126  * set the pointer being freed to NULL in the calling function.
127  *
128  * Many of these functions have a further isc___mem_<function>
129  * (three underscores) implementation, which is called indirectly
130  * via the isc_memmethods structure in the mctx so that dynamically
131  * loaded modules can use them even if named is statically linked.
132  */
133 
134 #define ISCMEMFUNC(sfx)	    isc__mem_##sfx
135 #define ISCMEMPOOLFUNC(sfx) isc__mempool_##sfx
136 
137 #define isc_mem_get(c, s) ISCMEMFUNC(get)((c), (s)_ISC_MEM_FILELINE)
138 #define isc_mem_reget(c, p, o, n) \
139 	ISCMEMFUNC(reget)((c), (p), (o), (n)_ISC_MEM_FILELINE)
140 #define isc_mem_allocate(c, s) ISCMEMFUNC(allocate)((c), (s)_ISC_MEM_FILELINE)
141 #define isc_mem_reallocate(c, p, s) \
142 	ISCMEMFUNC(reallocate)((c), (p), (s)_ISC_MEM_FILELINE)
143 #define isc_mem_strdup(c, p) ISCMEMFUNC(strdup)((c), (p)_ISC_MEM_FILELINE)
144 #define isc_mem_strndup(c, p, l) \
145 	ISCMEMFUNC(strndup)((c), (p), (l)_ISC_MEM_FILELINE)
146 #define isc_mempool_get(c) ISCMEMPOOLFUNC(get)((c)_ISC_MEM_FILELINE)
147 
148 #define isc_mem_put(c, p, s)                                     \
149 	do {                                                     \
150 		ISCMEMFUNC(put)((c), (p), (s)_ISC_MEM_FILELINE); \
151 		(p) = NULL;                                      \
152 	} while (0)
153 #define isc_mem_putanddetach(c, p, s)                                     \
154 	do {                                                              \
155 		ISCMEMFUNC(putanddetach)((c), (p), (s)_ISC_MEM_FILELINE); \
156 		(p) = NULL;                                               \
157 	} while (0)
158 #define isc_mem_free(c, p)                                   \
159 	do {                                                 \
160 		ISCMEMFUNC(free)((c), (p)_ISC_MEM_FILELINE); \
161 		(p) = NULL;                                  \
162 	} while (0)
163 #define isc_mempool_put(c, p)                                   \
164 	do {                                                    \
165 		ISCMEMPOOLFUNC(put)((c), (p)_ISC_MEM_FILELINE); \
166 		(p) = NULL;                                     \
167 	} while (0)
168 
169 /*@{*/
170 #define isc_mem_create(cp) ISCMEMFUNC(create)((cp)_ISC_MEM_FILELINE)
171 void ISCMEMFUNC(create)(isc_mem_t **_ISC_MEM_FLARG);
172 
173 /*!<
174  * \brief Create a memory context.
175  *
176  * Requires:
177  * mctxp != NULL && *mctxp == NULL */
178 /*@}*/
179 
180 /*@{*/
181 void
182 isc_mem_attach(isc_mem_t *, isc_mem_t **);
183 #define isc_mem_detach(cp) ISCMEMFUNC(detach)((cp)_ISC_MEM_FILELINE)
184 void ISCMEMFUNC(detach)(isc_mem_t **_ISC_MEM_FLARG);
185 /*!<
186  * \brief Attach to / detach from a memory context.
187  *
188  * This is intended for applications that use multiple memory contexts
189  * in such a way that it is not obvious when the last allocations from
190  * a given context has been freed and destroying the context is safe.
191  *
192  * Most applications do not need to call these functions as they can
193  * simply create a single memory context at the beginning of main()
194  * and destroy it at the end of main(), thereby guaranteeing that it
195  * is not destroyed while there are outstanding allocations.
196  */
197 /*@}*/
198 
199 #define isc_mem_destroy(cp) ISCMEMFUNC(destroy)((cp)_ISC_MEM_FILELINE)
200 void ISCMEMFUNC(destroy)(isc_mem_t **_ISC_MEM_FLARG);
201 /*%<
202  * Destroy a memory context.
203  */
204 
205 void
206 isc_mem_stats(isc_mem_t *mctx, FILE *out);
207 /*%<
208  * Print memory usage statistics for 'mctx' on the stream 'out'.
209  */
210 
211 void
212 isc_mem_setdestroycheck(isc_mem_t *mctx, bool on);
213 /*%<
214  * If 'on' is true, 'mctx' will check for memory leaks when
215  * destroyed and abort the program if any are present.
216  */
217 
218 size_t
219 isc_mem_inuse(isc_mem_t *mctx);
220 /*%<
221  * Get an estimate of the amount of memory in use in 'mctx', in bytes.
222  * This includes quantization overhead, but does not include memory
223  * allocated from the system but not yet used.
224  */
225 
226 size_t
227 isc_mem_maxinuse(isc_mem_t *mctx);
228 /*%<
229  * Get an estimate of the largest amount of memory that has been in
230  * use in 'mctx' at any time.
231  */
232 
233 size_t
234 isc_mem_total(isc_mem_t *mctx);
235 /*%<
236  * Get the total amount of memory in 'mctx', in bytes, including memory
237  * not yet used.
238  */
239 
240 size_t
241 isc_mem_malloced(isc_mem_t *ctx);
242 /*%<
243  * Get an estimate of the amount of memory allocated in 'mctx', in bytes.
244  */
245 
246 size_t
247 isc_mem_maxmalloced(isc_mem_t *ctx);
248 /*%<
249  * Get an estimate of the largest amount of memory that has been
250  * allocated in 'mctx' at any time.
251  */
252 
253 bool
254 isc_mem_isovermem(isc_mem_t *mctx);
255 /*%<
256  * Return true iff the memory context is in "over memory" state, i.e.,
257  * a hiwater mark has been set and the used amount of memory has exceeds
258  * the mark.
259  */
260 
261 void
262 isc_mem_clearwater(isc_mem_t *mctx);
263 void
264 isc_mem_setwater(isc_mem_t *mctx, isc_mem_water_t water, void *water_arg,
265 		 size_t hiwater, size_t lowater);
266 /*%<
267  * Set high and low water marks for this memory context.
268  *
269  * When the memory usage of 'mctx' exceeds 'hiwater',
270  * '(water)(water_arg, #ISC_MEM_HIWATER)' will be called.  'water' needs
271  * to call isc_mem_waterack() with #ISC_MEM_HIWATER to acknowledge the
272  * state change.  'water' may be called multiple times.
273  *
274  * When the usage drops below 'lowater', 'water' will again be called,
275  * this time with #ISC_MEM_LOWATER.  'water' need to calls
276  * isc_mem_waterack() with #ISC_MEM_LOWATER to acknowledge the change.
277  *
278  *	static void
279  *	water(void *arg, int mark) {
280  *		struct foo *foo = arg;
281  *
282  *		LOCK(&foo->marklock);
283  *		if (foo->mark != mark) {
284  *			foo->mark = mark;
285  *			....
286  *			isc_mem_waterack(foo->mctx, mark);
287  *		}
288  *		UNLOCK(&foo->marklock);
289  *	}
290  *
291  * if 'water' is set to NULL, the 'hiwater' and 'lowater' must set to 0, and
292  * high- and low-water processing are disabled for this memory context.  There's
293  * a convenient function isc_mem_clearwater().
294  *
295  * Requires:
296  *
297  *\li   If 'water' is NULL, 'hiwater' and 'lowater' must be set to 0.
298  *\li	If 'water' and 'water_arg' have previously been set, they are
299 	unchanged.
300  *\li	'hiwater' >= 'lowater'
301  */
302 
303 void
304 isc_mem_waterack(isc_mem_t *ctx, int mark);
305 /*%<
306  * Called to acknowledge changes in signaled by calls to 'water'.
307  */
308 
309 void
310 isc_mem_checkdestroyed(FILE *file);
311 /*%<
312  * Check that all memory contexts have been destroyed.
313  * Prints out those that have not been.
314  * Fatally fails if there are still active contexts.
315  */
316 
317 unsigned int
318 isc_mem_references(isc_mem_t *ctx);
319 /*%<
320  * Return the current reference count.
321  */
322 
323 void
324 isc_mem_setname(isc_mem_t *ctx, const char *name);
325 /*%<
326  * Name 'ctx'.
327  *
328  * Notes:
329  *
330  *\li	Only the first 15 characters of 'name' will be copied.
331  *
332  * Requires:
333  *
334  *\li	'ctx' is a valid ctx.
335  */
336 
337 const char *
338 isc_mem_getname(isc_mem_t *ctx);
339 /*%<
340  * Get the name of 'ctx', as previously set using isc_mem_setname().
341  *
342  * Requires:
343  *\li	'ctx' is a valid ctx.
344  *
345  * Returns:
346  *\li	A non-NULL pointer to a null-terminated string.
347  * 	If the ctx has not been named, the string is
348  * 	empty.
349  */
350 
351 #ifdef HAVE_LIBXML2
352 int
353 isc_mem_renderxml(void *writer0);
354 /*%<
355  * Render all contexts' statistics and status in XML for writer.
356  */
357 #endif /* HAVE_LIBXML2 */
358 
359 #ifdef HAVE_JSON_C
360 isc_result_t
361 isc_mem_renderjson(void *memobj0);
362 /*%<
363  * Render all contexts' statistics and status in JSON.
364  */
365 #endif /* HAVE_JSON_C */
366 
367 /*
368  * Memory pools
369  */
370 
371 #define isc_mempool_create(c, s, mp) \
372 	isc__mempool_create((c), (s), (mp)_ISC_MEM_FILELINE)
373 void
374 isc__mempool_create(isc_mem_t *restrict mctx, const size_t element_size,
375 		    isc_mempool_t **mpctxp _ISC_MEM_FLARG);
376 /*%<
377  * Create a memory pool.
378  *
379  * Requires:
380  *\li	mctx is a valid memory context.
381  *\li	size > 0
382  *\li	mpctxp != NULL and *mpctxp == NULL
383  *
384  * Defaults:
385  *\li	freemax = 1
386  *\li	fillcount = 1
387  *
388  * Returns:
389  *\li	#ISC_R_NOMEMORY		-- not enough memory to create pool
390  *\li	#ISC_R_SUCCESS		-- all is well.
391  */
392 
393 #define isc_mempool_destroy(mp) isc__mempool_destroy((mp)_ISC_MEM_FILELINE)
394 void
395 isc__mempool_destroy(isc_mempool_t **restrict mpctxp _ISC_MEM_FLARG);
396 /*%<
397  * Destroy a memory pool.
398  *
399  * Requires:
400  *\li	mpctxp != NULL && *mpctxp is a valid pool.
401  *\li	The pool has no un"put" allocations outstanding
402  */
403 
404 void
405 isc_mempool_setname(isc_mempool_t *restrict mpctx, const char *name);
406 /*%<
407  * Associate a name with a memory pool.  At most 15 characters may be
408  *used.
409  *
410  * Requires:
411  *\li	mpctx is a valid pool.
412  *\li	name != NULL;
413  */
414 
415 /*
416  * The following functions get/set various parameters.  Note that due to
417  * the unlocked nature of pools these are potentially random values
418  *unless the imposed externally provided locking protocols are followed.
419  *
420  * Also note that the quota limits will not always take immediate
421  * effect.
422  *
423  * All functions require (in addition to other requirements):
424  *	mpctx is a valid memory pool
425  */
426 
427 unsigned int
428 isc_mempool_getfreemax(isc_mempool_t *restrict mpctx);
429 /*%<
430  * Returns the maximum allowed size of the free list.
431  */
432 
433 void
434 isc_mempool_setfreemax(isc_mempool_t *restrict mpctx, const unsigned int limit);
435 /*%<
436  * Sets the maximum allowed size of the free list.
437  */
438 
439 unsigned int
440 isc_mempool_getfreecount(isc_mempool_t *restrict mpctx);
441 /*%<
442  * Returns current size of the free list.
443  */
444 
445 unsigned int
446 isc_mempool_getallocated(isc_mempool_t *restrict mpctx);
447 /*%<
448  * Returns the number of items allocated from this pool.
449  */
450 
451 unsigned int
452 isc_mempool_getfillcount(isc_mempool_t *restrict mpctx);
453 /*%<
454  * Returns the number of items allocated as a block from the parent
455  * memory context when the free list is empty.
456  */
457 
458 void
459 isc_mempool_setfillcount(isc_mempool_t *restrict mpctx,
460 			 const unsigned int limit);
461 /*%<
462  * Sets the fillcount.
463  *
464  * Additional requirements:
465  *\li	limit > 0
466  */
467 
468 #if defined(UNIT_TESTING) && defined(malloc)
469 /*
470  * cmocka.h redefined malloc as a macro, we #undef it
471  * to avoid replacing ISC_ATTR_MALLOC with garbage.
472  */
473 #pragma push_macro("malloc")
474 #undef malloc
475 #define POP_MALLOC_MACRO 1
476 #endif
477 
478 /*
479  * Pseudo-private functions for use via macros.  Do not call directly.
480  */
481 void ISCMEMFUNC(putanddetach)(isc_mem_t **, void *, size_t _ISC_MEM_FLARG);
482 void ISCMEMFUNC(put)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
483 void ISCMEMFUNC(free)(isc_mem_t *, void *_ISC_MEM_FLARG);
484 
485 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(put), 2)
486 void *ISCMEMFUNC(get)(isc_mem_t *, size_t _ISC_MEM_FLARG);
487 
488 ISC_ATTR_DEALLOCATOR_IDX(ISCMEMFUNC(put), 2)
489 void *ISCMEMFUNC(reget)(isc_mem_t *, void *, size_t, size_t _ISC_MEM_FLARG);
490 
491 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
492 void *ISCMEMFUNC(allocate)(isc_mem_t *, size_t _ISC_MEM_FLARG);
493 
494 ISC_ATTR_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
495 void *ISCMEMFUNC(reallocate)(isc_mem_t *, void *, size_t _ISC_MEM_FLARG);
496 
497 ISC_ATTR_RETURNS_NONNULL
498 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
499 char *ISCMEMFUNC(strdup)(isc_mem_t *, const char *_ISC_MEM_FLARG);
500 
501 ISC_ATTR_RETURNS_NONNULL
502 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMFUNC(free), 2)
503 char *ISCMEMFUNC(strndup)(isc_mem_t *, const char *, size_t _ISC_MEM_FLARG);
504 
505 ISC_ATTR_MALLOC_DEALLOCATOR_IDX(ISCMEMPOOLFUNC(put), 2)
506 void *ISCMEMPOOLFUNC(get)(isc_mempool_t *_ISC_MEM_FLARG);
507 
508 void ISCMEMPOOLFUNC(put)(isc_mempool_t *, void *_ISC_MEM_FLARG);
509 
510 #ifdef POP_MALLOC_MACRO
511 /*
512  * Restore cmocka.h macro for malloc.
513  */
514 #pragma pop_macro("malloc")
515 #endif
516 
517 ISC_LANG_ENDDECLS
518 
519 #endif /* ISC_MEM_H */
520