astmm.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. /*
  2. * Asterisk -- A telephony toolkit for Linux.
  3. *
  4. * Channel Variables
  5. *
  6. * Copyright (C) 2002, Mark Spencer
  7. *
  8. * Mark Spencer <markster@linux-support.net>
  9. *
  10. * This program is free software, distributed under the terms of
  11. * the GNU General Public License
  12. */
  13. #ifdef __AST_DEBUG_MALLOC
  14. #include <malloc.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <pthread.h>
  18. #include <time.h>
  19. #include <asterisk/cli.h>
  20. #include <asterisk/logger.h>
  21. #include <asterisk/options.h>
  22. #include <asterisk/lock.h>
  23. #define SOME_PRIME 563
  24. #define FUNC_CALLOC 1
  25. #define FUNC_MALLOC 2
  26. #define FUNC_REALLOC 3
  27. #define FUNC_STRDUP 4
  28. #define FUNC_STRNDUP 5
  29. #define FUNC_VASPRINTF 6
  30. /* Undefine all our macros */
  31. #undef malloc
  32. #undef calloc
  33. #undef realloc
  34. #undef strdup
  35. #undef strndup
  36. #undef free
  37. #undef vasprintf
  38. static FILE *mmlog;
  39. static struct ast_region {
  40. struct ast_region *next;
  41. char file[40];
  42. char func[40];
  43. int lineno;
  44. int which;
  45. size_t len;
  46. unsigned char data[0];
  47. } *regions[SOME_PRIME];
  48. #define HASH(a) \
  49. (((unsigned long)(a)) % SOME_PRIME)
  50. static ast_mutex_t reglock = AST_MUTEX_INITIALIZER;
  51. static ast_mutex_t showmemorylock = AST_MUTEX_INITIALIZER;
  52. static inline void *__ast_alloc_region(size_t size, int which, const char *file, int lineno, const char *func)
  53. {
  54. struct ast_region *reg;
  55. void *ptr=NULL;
  56. int hash;
  57. reg = malloc(size + sizeof(struct ast_region));
  58. ast_mutex_lock(&reglock);
  59. if (reg) {
  60. strncpy(reg->file, file, sizeof(reg->file) - 1);
  61. reg->file[sizeof(reg->file) - 1] = '\0';
  62. strncpy(reg->func, func, sizeof(reg->func) - 1);
  63. reg->func[sizeof(reg->func) - 1] = '\0';
  64. reg->lineno = lineno;
  65. reg->len = size;
  66. reg->which = which;
  67. ptr = reg->data;
  68. hash = HASH(ptr);
  69. reg->next = regions[hash];
  70. regions[hash] = reg;
  71. }
  72. ast_mutex_unlock(&reglock);
  73. if (!reg) {
  74. fprintf(stderr, "Out of memory :(\n");
  75. if (mmlog) {
  76. fprintf(mmlog, "%ld - Out of memory\n", time(NULL));
  77. fflush(mmlog);
  78. }
  79. }
  80. return ptr;
  81. }
  82. static inline size_t __ast_sizeof_region(void *ptr)
  83. {
  84. int hash = HASH(ptr);
  85. struct ast_region *reg;
  86. size_t len = 0;
  87. ast_mutex_lock(&reglock);
  88. reg = regions[hash];
  89. while(reg) {
  90. if (reg->data == ptr) {
  91. len = reg->len;
  92. break;
  93. }
  94. reg = reg->next;
  95. }
  96. ast_mutex_unlock(&reglock);
  97. return len;
  98. }
  99. static void __ast_free_region(void *ptr, const char *file, int lineno, const char *func)
  100. {
  101. int hash = HASH(ptr);
  102. struct ast_region *reg, *prev = NULL;
  103. ast_mutex_lock(&reglock);
  104. reg = regions[hash];
  105. while(reg) {
  106. if (reg->data == ptr) {
  107. if (prev)
  108. prev->next = reg->next;
  109. else
  110. regions[hash] = reg->next;
  111. break;
  112. }
  113. prev = reg;
  114. reg = reg->next;
  115. }
  116. ast_mutex_unlock(&reglock);
  117. if (reg) {
  118. free(reg);
  119. } else {
  120. fprintf(stderr, "WARNING: Freeing unused memory at %p, in %s of %s, line %d\n",
  121. ptr, func, file, lineno);
  122. if (mmlog) {
  123. fprintf(mmlog, "%ld - WARNING: Freeing unused memory at %p, in %s of %s, line %d\n", time(NULL),
  124. ptr, func, file, lineno);
  125. fflush(mmlog);
  126. }
  127. }
  128. }
  129. void *__ast_calloc(size_t nmemb, size_t size, const char *file, int lineno, const char *func)
  130. {
  131. void *ptr;
  132. ptr = __ast_alloc_region(size * nmemb, FUNC_CALLOC, file, lineno, func);
  133. if (ptr)
  134. memset(ptr, 0, size * nmemb);
  135. return ptr;
  136. }
  137. void *__ast_malloc(size_t size, const char *file, int lineno, const char *func)
  138. {
  139. return __ast_alloc_region(size, FUNC_MALLOC, file, lineno, func);
  140. }
  141. void __ast_free(void *ptr, const char *file, int lineno, const char *func)
  142. {
  143. __ast_free_region(ptr, file, lineno, func);
  144. }
  145. void *__ast_realloc(void *ptr, size_t size, const char *file, int lineno, const char *func)
  146. {
  147. void *tmp;
  148. size_t len=0;
  149. if (ptr) {
  150. len = __ast_sizeof_region(ptr);
  151. if (!len) {
  152. fprintf(stderr, "WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
  153. ptr, func, file, lineno);
  154. if (mmlog) {
  155. fprintf(mmlog, "%ld - WARNING: Realloc of unalloced memory at %p, in %s of %s, line %d\n",
  156. time(NULL), ptr, func, file, lineno);
  157. fflush(mmlog);
  158. }
  159. return NULL;
  160. }
  161. }
  162. tmp = __ast_alloc_region(size, FUNC_REALLOC, file, lineno, func);
  163. if (tmp) {
  164. if (len > size)
  165. len = size;
  166. if (ptr) {
  167. memcpy(tmp, ptr, len);
  168. __ast_free_region(ptr, file, lineno, func);
  169. }
  170. }
  171. return tmp;
  172. }
  173. char *__ast_strdup(const char *s, const char *file, int lineno, const char *func)
  174. {
  175. size_t len;
  176. void *ptr;
  177. if (!s)
  178. return NULL;
  179. len = strlen(s) + 1;
  180. ptr = __ast_alloc_region(len, FUNC_STRDUP, file, lineno, func);
  181. if (ptr)
  182. strcpy(ptr, s);
  183. return ptr;
  184. }
  185. char *__ast_strndup(const char *s, size_t n, const char *file, int lineno, const char *func)
  186. {
  187. size_t len;
  188. void *ptr;
  189. if (!s)
  190. return NULL;
  191. len = strlen(s) + 1;
  192. if (len > n)
  193. len = n;
  194. ptr = __ast_alloc_region(len, FUNC_STRNDUP, file, lineno, func);
  195. if (ptr)
  196. strcpy(ptr, s);
  197. return ptr;
  198. }
  199. int __ast_vasprintf(char **strp, const char *fmt, va_list ap, const char *file, int lineno, const char *func)
  200. {
  201. int n, size = strlen(fmt) + 1;
  202. if ((*strp = __ast_alloc_region(size, FUNC_VASPRINTF, file, lineno, func)) == NULL)
  203. return -1;
  204. for (;;) {
  205. n = vsnprintf(*strp, size, fmt, ap);
  206. if (n > -1 && n < size)
  207. return n;
  208. if (n > -1) /* glibc 2.1 */
  209. size = n+1;
  210. else /* glibc 2.0 */
  211. size *= 2;
  212. if ((*strp = __ast_realloc(*strp, size, file, lineno, func)) == NULL)
  213. return -1;
  214. }
  215. }
  216. static int handle_show_memory(int fd, int argc, char *argv[])
  217. {
  218. char *fn = NULL;
  219. int x;
  220. struct ast_region *reg;
  221. unsigned int len=0;
  222. int count = 0;
  223. if (argc >3)
  224. fn = argv[3];
  225. /* try to lock applications list ... */
  226. ast_mutex_lock(&showmemorylock);
  227. for (x=0;x<SOME_PRIME;x++) {
  228. reg = regions[x];
  229. while(reg) {
  230. if (!fn || !strcasecmp(fn, reg->file)) {
  231. ast_cli(fd, "%10d bytes allocated in %20s at line %5d of %s\n", reg->len, reg->func, reg->lineno, reg->file);
  232. len += reg->len;
  233. count++;
  234. }
  235. reg = reg->next;
  236. }
  237. }
  238. ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
  239. ast_mutex_unlock(&showmemorylock);
  240. return RESULT_SUCCESS;
  241. }
  242. struct file_summary {
  243. char fn[80];
  244. int len;
  245. int count;
  246. struct file_summary *next;
  247. };
  248. static int handle_show_memory_summary(int fd, int argc, char *argv[])
  249. {
  250. char *fn = NULL;
  251. int x;
  252. struct ast_region *reg;
  253. unsigned int len=0;
  254. int count = 0;
  255. struct file_summary *list = NULL, *cur;
  256. if (argc >3)
  257. fn = argv[3];
  258. /* try to lock applications list ... */
  259. ast_mutex_lock(&reglock);
  260. for (x=0;x<SOME_PRIME;x++) {
  261. reg = regions[x];
  262. while(reg) {
  263. if (!fn || !strcasecmp(fn, reg->file)) {
  264. cur = list;
  265. while(cur) {
  266. if ((!fn && !strcmp(cur->fn, reg->file)) || (fn && !strcmp(cur->fn, reg->func)))
  267. break;
  268. cur = cur->next;
  269. }
  270. if (!cur) {
  271. cur = alloca(sizeof(struct file_summary));
  272. memset(cur, 0, sizeof(struct file_summary));
  273. strncpy(cur->fn, fn ? reg->func : reg->file, sizeof(cur->fn) - 1);
  274. cur->next = list;
  275. list = cur;
  276. }
  277. cur->len += reg->len;
  278. cur->count++;
  279. }
  280. reg = reg->next;
  281. }
  282. }
  283. ast_mutex_unlock(&reglock);
  284. /* Dump the whole list */
  285. while(list) {
  286. cur = list;
  287. len += list->len;
  288. count += list->count;
  289. if (fn)
  290. ast_cli(fd, "%10d bytes in %5d allocations in function '%s' of '%s'\n", list->len, list->count, list->fn, fn);
  291. else
  292. ast_cli(fd, "%10d bytes in %5d allocations in file '%s'\n", list->len, list->count, list->fn);
  293. list = list->next;
  294. #if 0
  295. free(cur);
  296. #endif
  297. }
  298. ast_cli(fd, "%d bytes allocated %d units total\n", len, count);
  299. return RESULT_SUCCESS;
  300. }
  301. static char show_memory_help[] =
  302. "Usage: show memory allocations [<file>]\n"
  303. " Dumps a list of all segments of allocated memory, optionally\n"
  304. "limited to those from a specific file\n";
  305. static char show_memory_summary_help[] =
  306. "Usage: show memory summary [<file>]\n"
  307. " Summarizes heap memory allocations by file, or optionally\n"
  308. "by function, if a file is specified\n";
  309. static struct ast_cli_entry show_memory_allocations_cli =
  310. { { "show", "memory", "allocations", NULL },
  311. handle_show_memory, "Display outstanding memory allocations",
  312. show_memory_help };
  313. static struct ast_cli_entry show_memory_summary_cli =
  314. { { "show", "memory", "summary", NULL },
  315. handle_show_memory_summary, "Summarize outstanding memory allocations",
  316. show_memory_summary_help };
  317. void __ast_mm_init(void)
  318. {
  319. ast_cli_register(&show_memory_allocations_cli);
  320. ast_cli_register(&show_memory_summary_cli);
  321. mmlog = fopen("/var/log/asterisk/mmlog", "a+");
  322. if (option_verbose)
  323. ast_verbose("Asterisk Malloc Debugger Started (see /var/log/asterisk/mmlog)\n");
  324. if (mmlog) {
  325. fprintf(mmlog, "%ld - New session\n", time(NULL));
  326. fflush(mmlog);
  327. }
  328. }
  329. #endif