/* mem.c -- handles: memory allocation and deallocation keeping track of what memory is being used by whom dprintf'ized, 15nov95 */ /* This file is part of the eggdrop source code copyright (c) 1997 Robey Pointer and is distributed according to the GNU general public license. For full details, read the top of 'main.c' or the file called COPYING that was distributed with this code. */ #define LOG_MISC 32 #define MEMTBLSIZE 25000 /* yikes! */ #ifdef EBUG_MEM #define DEBUG #endif #if HAVE_CONFIG_H #include #endif #include #include #include #ifdef MODULES typedef int (*Function) (); #include "mod/modvals.h" extern module_entry *module_list; #endif extern int serv; #ifdef DEBUG unsigned long memused = 0; static int lastused = 0; struct { void *ptr; short size; char file[15]; short line; } memtbl[MEMTBLSIZE]; #endif #ifdef STDC_HEADERS #define PROTO(x) x #define PROTO1(a,b) (a b) #define PROTO2(a1,b1,a2,b2) (a1 b1, a2 b2) #define PROTO3(a1,b1,a2,b2,a3,b3) (a1 b1, a2 b2, a3 b3) #define PROTO4(a1,b1,a2,b2,a3,b3,a4,b4) \ (a1 b1, a2 b2, a3 b3, a4 b4) #define PROTO5(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5) \ (a1 b1, a2 b2, a3 b3, a4 b4, a5 b5) #define PROTO6(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6) \ (a1 b1, a2 b2, a3 b3, a4 b4, a5 b5, a6 b6) #else #define PROTO(x) () #define PROTO1(a,b) (b) a b; #define PROTO2(a1,b1,a2,b2) (b1, b2) a1 b1; a2 b2; #define PROTO3(a1,b1,a2,b2,a3,b3) (b1, b2, b3) a1 b1; a2 b2; a3 b3; #define PROTO4(a1,b1,a2,b2,a3,b3,a4,b4) (b1, b2, b3, b4) \ a1 b1; a2 b2; a3 b3; a4 b4; #define PROTO5(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5) \ (b1, b2, b3, b4, b5) \ a1 b1; a2 b2; a3 b3; a4 b4; a5 b5; #define PROTO6(a1,b1,a2,b2,a3,b3,a4,b4,a5,b5,a6,b6) \ (b1, b2, b3, b4, b5, b6) \ a1 b1; a2 b2; a3 b3; a4 b4; a5 b5; a6 b6; #endif #ifdef HAVE_DPRINTF #define dprintf dprintf_eggdrop #endif /* prototypes */ void mprintf(); void tprintf(); void dprintf(); void putlog(); int expected_memory(); int expmem_chan(); int expmem_chanprog(); int expmem_misc(); int expmem_fileq(); int expmem_users(); int expmem_dccutil(); int expmem_botnet(); int expmem_tcl(); int expmem_tclhash(); int expmem_net(); int expmem_blowfish(); int expmem_modules(); int expmem_assoc(); void tell_netdebug(); void debug_blowfish(); void do_module_report(); /* initialize the memory structure */ void init_mem() { #ifdef DEBUG int i; for (i = 0; i < MEMTBLSIZE; i++) memtbl[i].ptr = NULL; #endif } /* tell someone the gory memory details */ void tell_mem_status PROTO1(char *, nick) { #ifdef DEBUG float per; per = ((lastused * 1.0) / (MEMTBLSIZE * 1.0)) * 100.0; mprintf(serv, "NOTICE %s :Memory table usage: %d/%d (%.1f%% full)\n", nick, lastused, MEMTBLSIZE, per); #endif mprintf(serv, "NOTICE %s :Think I'm using about %dk.\n", nick, (int) (expected_memory() / 1024)); } void tell_mem_status_dcc PROTO1(int, idx) { #ifdef DEBUG int exp; float per; exp = expected_memory(); /* in main.c ? */ per = ((lastused * 1.0) / (MEMTBLSIZE * 1.0)) * 100.0; dprintf(idx, "Memory table: %d/%d (%.1f%% full)\n", lastused, MEMTBLSIZE, per); per = ((exp * 1.0) / (memused * 1.0)) * 100.0; if (per != 100.0) dprintf(idx, "Memory fault: only accounting for %d/%ld (%.1f%%)\n", exp, memused, per); dprintf(idx, "Memory table itself occupies an additional %dk static\n", (int) (sizeof(memtbl) / 1024)); #endif } void debug_mem_to_dcc PROTO1(int, idx) { #ifdef DEBUG #ifdef MODULES #define MAX_MEM 10 #else #define MAX_MEM 12 #endif unsigned long exp[MAX_MEM], use[MAX_MEM], l; int i, j; char fn[20], sofar[81]; #ifdef MODULES module_entry *me; char *p; #endif exp[0] = expmem_chan(); exp[1] = expmem_chanprog(); exp[2] = expmem_misc(); exp[3] = expmem_users(); exp[4] = expmem_net(); exp[5] = expmem_dccutil(); exp[6] = expmem_botnet(); exp[7] = expmem_tcl(); exp[8] = expmem_tclhash(); #ifndef MODULES exp[9] = expmem_fileq(); exp[10] = expmem_blowfish(); exp[11] = expmem_assoc(); #else exp[9] = expmem_modules(1); for (me = module_list; me; me = me->next) me->mem_work = 0; #endif for (i = 0; i < MAX_MEM; i++) use[i] = 0; for (i = 0; i < lastused; i++) { strcpy(fn, memtbl[i].file); l = memtbl[i].size; if (strcasecmp(fn, "chanset.c") == 0) use[0] += l; else if (strcasecmp(fn, "chanprog.c") == 0) use[1] += l; else if (strcasecmp(fn, "misc.c") == 0) use[2] += l; else if (strcasecmp(fn, "userrec.c") == 0) use[3] += l; else if (strcasecmp(fn, "net.c") == 0) use[4] += l; else if (strcasecmp(fn, "dccutil.c") == 0) use[5] += l; else if (strcasecmp(fn, "botnet.c") == 0) use[6] += l; else if (strcasecmp(fn, "tcl.c") == 0) use[7] += l; else if (strcasecmp(fn, "tclhash.c") == 0) use[8] += l; #ifndef MODULES else if (strcasecmp(fn, "fileq.c") == 0) use[9] += l; else if (strcasecmp(fn, "blowfish.c") == 0) use[10] += l; else if (strcasecmp(fn, "assoc.c") == 0) use[11] += l; #else else if (strcasecmp(fn, "modules.c") == 0) use[9] += l; else if ((p = strchr(fn, ':')) != NULL) { *p = 0; for (me = module_list; me; me = me->next) if (strcmp(fn, me->name) == 0) me->mem_work += l; *p = ':'; } #endif else { if (idx < 0) tprintf(-idx, "Not logging file %s!\n", fn); else dprintf(idx, "Not logging file %s!\n", fn); } } for (i = 0; i < MAX_MEM; i++) { switch (i) { case 0: strcpy(fn, "chanset.c"); break; case 1: strcpy(fn, "chanprog.c"); break; case 2: strcpy(fn, "misc.c"); break; case 3: strcpy(fn, "userrec.c"); break; case 4: strcpy(fn, "net.c"); break; case 5: strcpy(fn, "dccutil.c"); break; case 6: strcpy(fn, "botnet.c"); break; case 7: strcpy(fn, "tcl.c"); break; case 8: strcpy(fn, "tclhash.c"); break; #ifndef MODULES case 9: strcpy(fn, "fileq.c"); break; case 10: strcpy(fn, "blowfish.c"); break; case 11: strcpy(fn, "assoc.c"); break; #else case 9: strcpy(fn, "modules.c"); break; #endif } if (use[i] == exp[i]) { if (idx < 0) tprintf(-idx, "File '%-10s' accounted for %lu/%lu (ok)\n", fn, exp[i], use[i]); else dprintf(idx, "File '%-10s' accounted for %lu/%lu (ok)\n", fn, exp[i], use[i]); } else { if (idx < 0) tprintf(-idx, "File '%-10s' accounted for %lu/%lu (debug follows:)\n", fn, exp[i], use[i]); else dprintf(idx, "File '%-10s' accounted for %lu/%lu (debug follows:)\n", fn, exp[i], use[i]); strcpy(sofar, " "); for (j = 0; j < lastused; j++) if (strcasecmp(memtbl[j].file, fn) == 0) { sprintf(&sofar[strlen(sofar)], "%-3d:(%03X) ", memtbl[j].line, memtbl[j].size); if (strlen(sofar) > 60) { sofar[strlen(sofar) - 1] = 0; if (idx < 0) tprintf(-idx, "%s\n", sofar); else dprintf(idx, "%s\n", sofar); strcpy(sofar, " "); } } if (sofar[0]) { sofar[strlen(sofar) - 1] = 0; if (idx < 0) tprintf(-idx, "%s\n", sofar); else dprintf(idx, "%s\n", sofar); } } } #ifdef MODULES for (me = module_list; me; me = me->next) { Function *f = me->funcs; int expt = 0; if ((f != NULL) && (f[MODCALL_EXPMEM] != NULL)) expt = f[MODCALL_EXPMEM] (); if (me->mem_work == expt) { dprintf(idx, "Module '%-10s' accounted for %lu/%lu (ok)\n", me->name, expt, me->mem_work); } else { dprintf(idx, "Module '%-10s' accounted for %lu/%lu (debug follows:)\n", me->name, expt, me->mem_work); strcpy(sofar, " "); for (j = 0; j < lastused; j++) { strcpy(fn, memtbl[j].file); if ((p = strchr(fn, ':')) != NULL) { *p = 0; if (strcasecmp(fn, me->name) == 0) { sprintf(&sofar[strlen(sofar)], "%-10s/%-3d:(%03X) ", p + 1, memtbl[j].line, memtbl[j].size); if (strlen(sofar) > 60) { sofar[strlen(sofar) - 1] = 0; dprintf(idx, "%s\n", sofar); strcpy(sofar, " "); } *p = ':'; } } } if (sofar[0]) { sofar[strlen(sofar) - 1] = 0; dprintf(idx, "%s\n", sofar); } } } #endif if (idx < 0) tprintf(-idx, "--- End of debug memory list.\n"); else dprintf(idx, "--- End of debug memory list.\n"); #else if (idx < 0) tprintf(-idx, "Compiled without debug info.\n"); else dprintf(idx, "Compiled without extensive memory debugging (sorry).\n"); #endif tell_netdebug(idx); #ifdef MODULES do_module_report(idx); #else debug_blowfish(idx); #endif } void *n_malloc PROTO3(int, size, char *, file, int, line) { void *x; int i = 0; x = (void *) malloc(size); if (x == NULL) { i = i; putlog(LOG_MISC, "*", "*** FAILED MALLOC %s (%d)", file, line); return NULL; } #ifdef DEBUG if (lastused == MEMTBLSIZE) { putlog(LOG_MISC, "*", "*** MEMORY TABLE FULL: %s (%d)", file, line); return x; } i = lastused; memtbl[i].ptr = x; memtbl[i].line = line; memtbl[i].size = size; strcpy(memtbl[i].file, file); memused += size; lastused++; #endif return x; } void *n_realloc PROTO4(void *, ptr, int, size, char *, file, int, line) { void *x; int i = 0; x = (void *) realloc(ptr, size); if (x == NULL) { i = i; putlog(LOG_MISC, "*", "*** FAILED REALLOC %s (%d)", file, line); return NULL; } #ifdef DEBUG for (i = 0; (i < lastused) && (memtbl[i].ptr != ptr); i++); if (i == lastused) { putlog(LOG_MISC, "*", "*** ATTEMPTING TO REALLOC NON-MALLOC'D PTR: %s (%d)", file, line); return NULL; } memused -= memtbl[i].size; memtbl[i].ptr = x; memtbl[i].line = line; memtbl[i].size = size; strcpy(memtbl[i].file, file); memused += size; #endif return x; } void n_free PROTO3(void *, ptr, char *, file, int, line) { int i = 0; if (ptr == NULL) { putlog(LOG_MISC, "*", "*** ATTEMPTING TO FREE NULL PTR: %s (%d)", file, line); i = i; return; } #ifdef DEBUG /* give tcl builtins an escape mechanism */ if (line) { for (i = 0; (i < lastused) && (memtbl[i].ptr != ptr); i++); if (i == lastused) { putlog(LOG_MISC, "*", "*** ATTEMPTING TO FREE NON-MALLOC'D PTR: %s (%d)", file, line); return; } memused -= memtbl[i].size; lastused--; memtbl[i].ptr = memtbl[lastused].ptr; memtbl[i].size = memtbl[lastused].size; memtbl[i].line = memtbl[lastused].line; strcpy(memtbl[i].file, memtbl[lastused].file); } #endif free(ptr); }