📄 alloc.c
字号:
/* alloc.c Functions supporting memory allocation for the object management protocol... *//* * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") * Copyright (c) 1999-2003 by Internet Software Consortium * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Internet Systems Consortium, Inc. * 950 Charter Street * Redwood City, CA 94063 * <info@isc.org> * http://www.isc.org/ * * This software has been written for Internet Systems Consortium * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc. * To learn more about Internet Systems Consortium, see * ``http://www.isc.org/''. To learn more about Vixie Enterprises, * see ``http://www.vix.com''. To learn more about Nominum, Inc., see * ``http://www.nominum.com''. */#include <omapip/omapip_p.h>#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)struct dmalloc_preamble *dmalloc_list;unsigned long dmalloc_outstanding;unsigned long dmalloc_longterm;unsigned long dmalloc_generation;unsigned long dmalloc_cutoff_generation;#endif#if defined (DEBUG_RC_HISTORY)struct rc_history_entry rc_history [RC_HISTORY_MAX];int rc_history_index;int rc_history_count;#endif#if defined (DEBUG_RC_HISTORY)static void print_rc_hist_entry (int);#endifVOIDPTR dmalloc (size, file, line) unsigned size; const char *file; int line;{ unsigned char *foo = malloc (size + DMDSIZE); int i; VOIDPTR *bar;#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) struct dmalloc_preamble *dp;#endif if (!foo) return (VOIDPTR)0; bar = (VOIDPTR)(foo + DMDOFFSET); memset (bar, 0, size);#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) dp = (struct dmalloc_preamble *)foo; dp -> prev = dmalloc_list; if (dmalloc_list) dmalloc_list -> next = dp; dmalloc_list = dp; dp -> next = (struct dmalloc_preamble *)0; dp -> size = size; dp -> file = file; dp -> line = line; dp -> generation = dmalloc_generation++; dmalloc_outstanding += size; for (i = 0; i < DMLFSIZE; i++) dp -> low_fence [i] = (((unsigned long) (&dp -> low_fence [i])) % 143) + 113; for (i = DMDOFFSET; i < DMDSIZE; i++) foo [i + size] = (((unsigned long) (&foo [i + size])) % 143) + 113;#if defined (DEBUG_MALLOC_POOL_EXHAUSTIVELY) /* Check _every_ entry in the pool! Very expensive. */ for (dp = dmalloc_list; dp; dp = dp -> prev) { for (i = 0; i < DMLFSIZE; i++) { if (dp -> low_fence [i] != (((unsigned long) (&dp -> low_fence [i])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } foo = (unsigned char *)dp; for (i = DMDOFFSET; i < DMDSIZE; i++) { if (foo [i + dp -> size] != (((unsigned long) (&foo [i + dp -> size])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } }#endif#endif#ifdef DEBUG_REFCNT_DMALLOC_FREE rc_register (file, line, 0, foo + DMDOFFSET, 1, 0, RC_MALLOC);#endif return bar;}void dfree (ptr, file, line) VOIDPTR ptr; const char *file; int line;{ if (!ptr) { log_error ("dfree %s(%d): free on null pointer.", file, line); return; }#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) { unsigned char *bar = ptr; struct dmalloc_preamble *dp, *cur; int i; bar -= DMDOFFSET; cur = (struct dmalloc_preamble *)bar; for (dp = dmalloc_list; dp; dp = dp -> prev) if (dp == cur) break; if (!dp) { log_error ("%s(%d): freeing unknown memory: %lx", file, line, (unsigned long)cur); abort (); } if (dp -> prev) dp -> prev -> next = dp -> next; if (dp -> next) dp -> next -> prev = dp -> prev; if (dp == dmalloc_list) dmalloc_list = dp -> prev; if (dp -> generation >= dmalloc_cutoff_generation) dmalloc_outstanding -= dp -> size; else dmalloc_longterm -= dp -> size; for (i = 0; i < DMLFSIZE; i++) { if (dp -> low_fence [i] != (((unsigned long) (&dp -> low_fence [i])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } for (i = DMDOFFSET; i < DMDSIZE; i++) { if (bar [i + dp -> size] != (((unsigned long) (&bar [i + dp -> size])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } ptr = bar; }#endif#ifdef DEBUG_REFCNT_DMALLOC_FREE rc_register (file, line, 0, (unsigned char *)ptr + DMDOFFSET, 0, 1, RC_MALLOC);#endif free (ptr);}#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)/* For allocation functions that keep their own free lists, we want to account for the reuse of the memory. */void dmalloc_reuse (foo, file, line, justref) VOIDPTR foo; const char *file; int line; int justref;{ struct dmalloc_preamble *dp; /* Get the pointer to the dmalloc header. */ dp = foo; dp--; /* If we just allocated this and are now referencing it, this function would almost be a no-op, except that it would increment the generation count needlessly. So just return in this case. */ if (dp -> generation == dmalloc_generation) return; /* If this is longterm data, and we just made reference to it, don't put it on the short-term list or change its name - we don't need to know about this. */ if (dp -> generation < dmalloc_cutoff_generation && justref) return; /* Take it out of the place in the allocated list where it was. */ if (dp -> prev) dp -> prev -> next = dp -> next; if (dp -> next) dp -> next -> prev = dp -> prev; if (dp == dmalloc_list) dmalloc_list = dp -> prev; /* Account for its removal. */ if (dp -> generation >= dmalloc_cutoff_generation) dmalloc_outstanding -= dp -> size; else dmalloc_longterm -= dp -> size; /* Now put it at the head of the list. */ dp -> prev = dmalloc_list; if (dmalloc_list) dmalloc_list -> next = dp; dmalloc_list = dp; dp -> next = (struct dmalloc_preamble *)0; /* Change the reference location information. */ dp -> file = file; dp -> line = line; /* Increment the generation. */ dp -> generation = dmalloc_generation++; /* Account for it. */ dmalloc_outstanding += dp -> size;}void dmalloc_dump_outstanding (){ static unsigned long dmalloc_cutoff_point; struct dmalloc_preamble *dp; unsigned char *foo; int i; if (!dmalloc_cutoff_point) dmalloc_cutoff_point = dmalloc_cutoff_generation; for (dp = dmalloc_list; dp; dp = dp -> prev) { if (dp -> generation <= dmalloc_cutoff_point) break;#if defined (DEBUG_MALLOC_POOL) for (i = 0; i < DMLFSIZE; i++) { if (dp -> low_fence [i] != (((unsigned long) (&dp -> low_fence [i])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } } foo = (unsigned char *)dp; for (i = DMDOFFSET; i < DMDSIZE; i++) { if (foo [i + dp -> size] != (((unsigned long) (&foo [i + dp -> size])) % 143) + 113) { log_error ("malloc fence modified: %s(%d)", dp -> file, dp -> line); abort (); } }#endif#if defined (DEBUG_MEMORY_LEAKAGE) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT) /* Don't count data that's actually on a free list somewhere. */ if (dp -> file) {#if defined (DEBUG_RC_HISTORY) int i, count, inhistory = 0, noted = 0; /* If we have the info, see if this is actually new garbage. */ if (rc_history_count < RC_HISTORY_MAX) { count = rc_history_count; } else count = RC_HISTORY_MAX; i = rc_history_index - 1; if (i < 0) i += RC_HISTORY_MAX; do { if (rc_history [i].addr == dp + 1) { inhistory = 1; if (!noted) { log_info (" %s(%d): %d", dp -> file, dp -> line, dp -> size); noted = 1; } print_rc_hist_entry (i); if (!rc_history [i].refcnt) break; } if (--i < 0) i = RC_HISTORY_MAX - 1; } while (count--); if (!inhistory)#endif log_info (" %s(%d): %d", dp -> file, dp -> line, dp -> size); }#endif } if (dmalloc_list) dmalloc_cutoff_point = dmalloc_list -> generation;}#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */#if defined (DEBUG_RC_HISTORY)static void print_rc_hist_entry (int i){ log_info (" referenced by %s(%d)[%lx]: addr = %lx refcnt = %x", rc_history [i].file, rc_history [i].line, (unsigned long)rc_history [i].reference, (unsigned long)rc_history [i].addr, rc_history [i].refcnt);}void dump_rc_history (void *addr){ int i; i = rc_history_index; if (!rc_history [i].file) i = 0; else if (rc_history_count < RC_HISTORY_MAX) { i -= rc_history_count; if (i < 0) i += RC_HISTORY_MAX; } rc_history_count = 0; while (rc_history [i].file) { if (!addr || addr == rc_history [i].addr) print_rc_hist_entry (i); ++i; if (i == RC_HISTORY_MAX) i = 0; if (i == rc_history_index) break; }}void rc_history_next (int d){#if defined (RC_HISTORY_COMPRESSION) int i, j = 0, m, n = 0; void *ap, *rp; /* If we are decreasing the reference count, try to find the entry where the reference was made and eliminate it; then we can also eliminate this reference. */ if (d) { m = rc_history_index - 1000; if (m < -1) m = -1; ap = rc_history [rc_history_index].addr; rp = rc_history [rc_history_index].reference; for (i = rc_history_index - 1; i > m; i--) { if (rc_history [i].addr == ap) { if (rc_history [i].reference == rp) { if (n > 10) { for (n = i; n <= rc_history_index; n++) print_rc_hist_entry (n); n = 11; } memmove (&rc_history [i], &rc_history [i + 1], (unsigned)((rc_history_index - i) * sizeof (struct rc_history_entry))); --rc_history_count; --rc_history_index; for (j = i; j < rc_history_count; j++) { if (rc_history [j].addr == ap) --rc_history [j].refcnt; } if (n > 10) { for (n = i; n <= rc_history_index; n++) print_rc_hist_entry (n); n = 11; exit (0); } return; } } } }#endif if (++rc_history_index == RC_HISTORY_MAX) rc_history_index = 0; ++rc_history_count;}#endif#if defined (DEBUG_MEMORY_LEAKAGE) || defined (DEBUG_MALLOC_POOL) || \ defined (DEBUG_MEMORY_LEAKAGE_ON_EXIT)struct caller { struct dmalloc_preamble *dp; int count;};static int dmalloc_find_entry (struct dmalloc_preamble *dp, struct caller *array, int min, int max){ int middle; int cmp; middle = (min + max) / 2; if (middle == min) return middle; if (array [middle].dp -> file == dp -> file) { if (array [middle].dp -> line == dp -> line) return middle; else if (array [middle].dp -> line < dp -> line) return dmalloc_find_entry (dp, array, middle, max); else return dmalloc_find_entry (dp, array, 0, middle); } else if (array [middle].dp -> file < dp -> file) return dmalloc_find_entry (dp, array, middle, max); else return dmalloc_find_entry (dp, array, 0, middle);}void omapi_print_dmalloc_usage_by_caller (){ struct dmalloc_preamble *dp; unsigned char *foo; int ccur, cmax, i, j; struct caller cp [1024]; cmax = 1024; ccur = 0; memset (cp, 0, sizeof cp); for (dp = dmalloc_list; dp; dp = dp -> prev) { i = dmalloc_find_entry (dp, cp, 0, ccur); if ((i == ccur || cp [i].dp -> file != dp -> file || cp [i].dp -> line != dp -> line) && ccur == cmax) { log_error ("no space for memory usage summary."); return; } if (i == ccur) { cp [ccur++].dp = dp; cp [i].count = 1; } else if (cp [i].dp -> file < dp -> file || (cp [i].dp -> file == dp -> file && cp [i].dp -> line < dp -> line)) { if (i + 1 != ccur) memmove (cp + i + 2, cp + i + 1, (ccur - i) * sizeof *cp); cp [i + 1].dp = dp; cp [i + 1].count = 1; ccur++; } else if (cp [i].dp -> file != dp -> file || cp [i].dp -> line != dp -> line) { memmove (cp + i + 1, cp + i, (ccur - i) * sizeof *cp); cp [i].dp = dp; cp [i].count = 1; ccur++; } else cp [i].count++;#if 0 printf ("%d\t%s:%d\n", i, dp -> file, dp -> line); dump_rc_history (dp + 1);#endif } for (i = 0; i < ccur; i++) { printf ("%d\t%s:%d\t%d\n", i, cp [i].dp -> file, cp [i].dp -> line, cp [i].count); dump_rc_history (cp [i].dp + 1); }}#endif /* DEBUG_MEMORY_LEAKAGE || DEBUG_MALLOC_POOL */isc_result_t omapi_object_allocate (omapi_object_t **o, omapi_object_type_t *type, size_t size, const char *file, int line){ size_t tsize; omapi_object_t *foo; isc_result_t status; if (type -> allocator) { foo = (omapi_object_t *)0; status = (*type -> allocator) (&foo, file, line); tsize = type -> size; } else status = ISC_R_NOMEMORY; if (status == ISC_R_NOMEMORY) { if (type -> sizer) tsize = (*type -> sizer) (size); else tsize = type -> size; /* Sanity check. */ if (tsize < sizeof (omapi_object_t)) return ISC_R_INVALIDARG; foo = dmalloc (tsize, file, line); if (!foo) return ISC_R_NOMEMORY; } status = omapi_object_initialize (foo, type, size, tsize, file, line); if (status != ISC_R_SUCCESS) { if (type -> freer) (*type -> freer) (foo, file, line); else dfree (foo, file, line); return status; } return omapi_object_reference (o, foo, file, line);}isc_result_t omapi_object_initialize (omapi_object_t *o, omapi_object_type_t *type, size_t usize, size_t psize, const char *file, int line){ memset (o, 0, psize); o -> type = type; if (type -> initialize) (*type -> initialize) (o, file, line); return ISC_R_SUCCESS;}isc_result_t omapi_object_reference (omapi_object_t **r, omapi_object_t *h, const char *file, int line){ if (!h || !r) return ISC_R_INVALIDARG; if (*r) {#if defined (POINTER_DEBUG) log_error ("%s(%d): reference store into non-null pointer!", file, line); abort ();#else return ISC_R_INVALIDARG;#endif } *r = h; h -> refcnt++; rc_register (file, line, r, h, h -> refcnt, 0, h -> type -> rc_flag);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -