aug_alloc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631
  1. /*
  2. * $Id$
  3. *
  4. * POSTGRES module, portions of this code were templated using
  5. * the mysql module, thus it's similarity.
  6. *
  7. *
  8. * Copyright (C) 2003 August.Net Services, LLC
  9. *
  10. * This file is part of ser, a free SIP server.
  11. *
  12. * ser is free software; you can redistribute it and/or modify
  13. * it under the terms of the GNU General Public License as published by
  14. * the Free Software Foundation; either version 2 of the License, or
  15. * (at your option) any later version
  16. *
  17. * For a license to use the ser software under conditions
  18. * other than those described here, or to purchase support for this
  19. * software, please contact iptel.org by e-mail at the following addresses:
  20. * [email protected]
  21. *
  22. * ser is distributed in the hope that it will be useful,
  23. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  24. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  25. * GNU General Public License for more details.
  26. *
  27. * You should have received a copy of the GNU General Public License
  28. * along with this program; if not, write to the Free Software
  29. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  30. *
  31. * ---
  32. *
  33. * History
  34. * -------
  35. * 2003-04-06 initial code written (Greg Fausak/Andy Fullford)
  36. *
  37. */
  38. /*
  39. ** ________________________________________________________________________
  40. **
  41. **
  42. ** $RCSfile$
  43. ** $Revision$
  44. **
  45. ** Last change $Date$
  46. ** Last change $Author$
  47. ** $State$
  48. ** $Locker$
  49. **
  50. ** Original author: Andrew Fullford
  51. **
  52. ** Copyright (C) August Associates 1995
  53. **
  54. ** ________________________________________________________________________
  55. */
  56. #include "aug_std.h"
  57. #include <stdlib.h>
  58. #include <stdio.h>
  59. #include <string.h>
  60. typedef double MemAlign;
  61. typedef augUInt32 MemMagic;
  62. typedef union MemHead MemHead;
  63. typedef struct MemOpt MemOpt;
  64. typedef struct MemDestructor MemDestructor; /* not yet implemented */
  65. /*
  66. ** One of these MemHead structs is allocated at the head of
  67. ** each alloc, plus an extra magic number at the end area.
  68. ** This gives an allocation overhead of:
  69. **
  70. ** malloc_overhead + sizeof MemHead + sizeof MemMagic
  71. **
  72. ** "Notes" entry for the man page: the allocation overhead is way
  73. ** too high. (On a 32bit machine and assuming a malloc overhead
  74. ** of 8 bytes, the total will be 8 + 32 + 4 = 44 bytes).
  75. */
  76. struct MemHeadStruct
  77. {
  78. MemHead *parent, *sibling, *child;
  79. MemOpt *options;
  80. char *end;
  81. char *file;
  82. augUInt32 line;
  83. MemMagic magic;
  84. };
  85. /*
  86. ** Attempt to guarantee alignment.
  87. */
  88. union MemHead
  89. {
  90. struct MemHeadStruct m;
  91. MemAlign align[1];
  92. };
  93. /*
  94. ** MemOpt holds optional features. The only current example
  95. ** is the memory destructor state.
  96. */
  97. struct MemOpt
  98. {
  99. MemMagic magic;
  100. MemDestructor *destructor_list;
  101. };
  102. /*
  103. ** These magic numbers are used to validate headers, force memory
  104. ** to a known state, etc.
  105. */
  106. #define MEM_MAGIC_BOUND 0xC0EDBABE
  107. #define MEM_MAGIC_FILL 0xDEADC0DE
  108. static int mem_bad(MemHead *mem, char *where, char *file, int line)
  109. {
  110. aug_abort(file, line, "Corrupted memory in %s", where);
  111. return 0;
  112. }
  113. /*
  114. ** Calculate the MemHead address given an aug_alloc() pointer.
  115. */
  116. #define MEM_CROWN(alloc) ((MemHead *)(((char *)alloc) - sizeof (MemHead)))
  117. #define MEM_DECAPITATE(mem) ((void *)(((char *)mem) + sizeof (MemHead)))
  118. static MemMagic mem_magic = MEM_MAGIC_BOUND;
  119. #define MEM_TAIL(p) (memcmp((p)->m.end,(char*)&mem_magic,sizeof mem_magic)==0)
  120. #define MEM_CHECK(p,w) ((p) && \
  121. ((p)->m.magic != MEM_MAGIC_BOUND || !MEM_TAIL(p)) && \
  122. mem_bad((p),(w),file,line))
  123. /* Initialize stats structure with estimated overhead */
  124. static augAllocStats mem_stats = {sizeof (MemHead) + sizeof (MemMagic) + 8, 0};
  125. static augNoMemFunc *mem_nomem_func = 0;
  126. static void mem_nomem(size_t size, char *func, char *file, int line)
  127. {
  128. static augBool active = augFALSE;
  129. char *module;
  130. if(!func)
  131. func = "unknown function";
  132. if(active)
  133. fprintf(stderr, "\r\n\nPANIC: nomem bounce\r\n\n");
  134. else
  135. {
  136. active = augTRUE;
  137. if(mem_nomem_func)
  138. (*mem_nomem_func)(size, func, file, line);
  139. }
  140. fprintf(stderr, "\r\n\n");
  141. module = aug_module();
  142. if(module && *module)
  143. fprintf(stderr, "FATAL in %s: ", module);
  144. else
  145. fprintf(stderr, "FATAL: ");
  146. fprintf(stderr, "%s failure allocating %lu bytes ", func, size);
  147. if(file && *file)
  148. fprintf(stderr, "from +%d %s \r\n", line, file);
  149. else
  150. fprintf(stderr, "(unknown location) \r\n");
  151. fprintf(stderr, " Current allocations: %10lu \r\n",
  152. (mem_stats.alloc_ops - mem_stats.free_ops));
  153. fprintf(stderr, " Total allocations: %10lu \r\n",
  154. mem_stats.alloc_ops);
  155. fprintf(stderr, " Total reallocations: %10lu \r\n",
  156. mem_stats.realloc_ops);
  157. fprintf(stderr, " Total frees: %10lu \r\n",
  158. mem_stats.free_ops);
  159. fprintf(stderr, "Estimated total heap use (KBytes): %10lu \r\n",
  160. (mem_stats.current_bytes_allocated +
  161. (mem_stats.alloc_ops - mem_stats.free_ops) *
  162. mem_stats.estimated_overhead_per_alloc + 512)/1024);
  163. fprintf(stderr, "\n");
  164. aug_exit(augEXIT_NOMEM);
  165. }
  166. static void *mem_alloc(size_t size, void *parent, char *file, int line)
  167. {
  168. MemHead *mem, *par;
  169. DABNAME("mem_alloc");
  170. if(parent)
  171. {
  172. par = MEM_CROWN(parent);
  173. MEM_CHECK(par, "parent");
  174. MEM_CHECK(par->m.child, "sibling");
  175. MEM_CHECK(par->m.sibling, "uncle");
  176. }
  177. else
  178. par = 0;
  179. mem_stats.current_bytes_allocated += size;
  180. mem_stats.alloc_ops++;
  181. /* Adjust for overhead */
  182. size += sizeof (MemHead);
  183. mem = malloc(size + sizeof (MemMagic));
  184. if(!mem)
  185. mem_nomem(size, "aug_alloc", file, line);
  186. if(DABLEVEL(DAB_STD))
  187. {
  188. unsigned long *p;
  189. p = (unsigned long *)mem;
  190. while((char *)p <= (char *)mem + size)
  191. *p++ = MEM_MAGIC_FILL;
  192. }
  193. mem->m.magic = MEM_MAGIC_BOUND;
  194. mem->m.file = file;
  195. mem->m.line = line;
  196. mem->m.end = (char *)mem + size;
  197. mem->m.options = 0;
  198. mem->m.child = 0;
  199. mem->m.parent = par;
  200. if(par)
  201. {
  202. if((mem->m.sibling = par->m.child))
  203. mem->m.sibling->m.parent = mem;
  204. par->m.child = mem;
  205. }
  206. else
  207. mem->m.sibling = 0;
  208. memcpy(mem->m.end, (char *)&mem_magic, sizeof mem_magic);
  209. return MEM_DECAPITATE(mem);
  210. }
  211. static void mem_free(MemHead *mem)
  212. {
  213. size_t size;
  214. DABNAME("mem_free");
  215. while(mem)
  216. {
  217. MemHead *next = mem->m.sibling;
  218. if(mem->m.child)
  219. mem_free(mem->m.child);
  220. size = (char *)mem->m.end - (char *)mem;
  221. size -= sizeof (MemHead) + sizeof (MemMagic);
  222. mem_stats.current_bytes_allocated -= size;
  223. mem_stats.free_ops++;
  224. if(DABLEVEL(DAB_STD))
  225. {
  226. unsigned long *p = (unsigned long *)(mem+1);
  227. while((char *)p <= mem->m.end)
  228. *p++ = MEM_MAGIC_FILL;
  229. p = (unsigned long *)mem;
  230. while(p < (unsigned long *)(mem+1))
  231. *p++ = MEM_MAGIC_FILL;
  232. }
  233. free(mem);
  234. mem = next;
  235. }
  236. }
  237. static augBool mem_find(MemHead *mem, MemHead *p)
  238. {
  239. while(mem)
  240. {
  241. MemHead *next;
  242. if(mem == p)
  243. return augTRUE;
  244. next = mem->m.sibling;
  245. if(mem->m.child)
  246. if(mem_find(mem->m.child, p))
  247. return augTRUE;
  248. mem = next;
  249. }
  250. return augFALSE;
  251. }
  252. augExport augNoMemFunc *aug_set_nomem_func(augNoMemFunc *new_func)
  253. {
  254. augNoMemFunc *old = mem_nomem_func;
  255. DABNAME("aug_set_nomem_func");
  256. mem_nomem_func = new_func;
  257. DABTRACE("New nomem func %08lx, previous %08lx",
  258. (unsigned long)mem_nomem_func, (unsigned long)old);
  259. return old;
  260. }
  261. augExport augAllocStats *aug_alloc_stats(void)
  262. {
  263. return &mem_stats;
  264. }
  265. augExport void *aug_alloc_loc(size_t size, void *parent, char *file, int line)
  266. {
  267. void *alloc;
  268. DABNAME("aug_alloc");
  269. DAB("size %lu, parent %08lx [+%d %s]",
  270. (unsigned long)size, (unsigned long)parent, line, file);
  271. alloc = mem_alloc(size, parent, file, line);
  272. DABL(80)("size %lu with header, caller mem at %08lx",
  273. MEM_CROWN(alloc)->m.end - (char *)MEM_CROWN(alloc),
  274. (unsigned long)alloc);
  275. return alloc;
  276. }
  277. augExport void *aug_realloc_loc(size_t size, void *prev, char *file, int line)
  278. {
  279. void *alloc;
  280. size_t prev_size;
  281. MemHead *mem, *par, *kid, *sib, *new;
  282. DABNAME("aug_realloc");
  283. if(!prev)
  284. aug_abort(file, line, "Attempt to realloc a NULL pointer");
  285. mem = MEM_CROWN(prev);
  286. MEM_CHECK(mem, "previous alloc");
  287. par = mem->m.parent; MEM_CHECK(par, "realloc parent");
  288. kid = mem->m.child; MEM_CHECK(kid, "realloc child");
  289. sib = mem->m.sibling; MEM_CHECK(sib, "realloc sibling");
  290. prev_size = (mem->m.end - (char *)mem) - sizeof (MemHead);
  291. DAB("prior size %lu, new %lu [+%d %s]",
  292. (unsigned long)prev_size, (unsigned long)size,
  293. line, file);
  294. DABL(80)("prior mem %08lx", (unsigned long)mem);
  295. mem_stats.current_bytes_allocated += size - prev_size;
  296. mem_stats.realloc_ops++;
  297. size += sizeof (MemHead);
  298. new = realloc(mem, size + sizeof (MemMagic));
  299. if(!new)
  300. mem_nomem(size, "aug_realloc", file, line);
  301. new->m.end = (char *)new + size;
  302. memcpy(new->m.end, (char *)&mem_magic, sizeof mem_magic);
  303. if(par)
  304. {
  305. if(par->m.sibling == mem)
  306. par->m.sibling = new;
  307. else
  308. par->m.child = new;
  309. }
  310. if(kid)
  311. kid->m.parent = new;
  312. if(sib)
  313. sib->m.parent = new;
  314. alloc = MEM_DECAPITATE(new);
  315. DABL(80)("size %lu with header, caller mem at %08lx",
  316. new->m.end - (char *)new, (unsigned long)alloc);
  317. return alloc;
  318. }
  319. augExport void aug_free_loc(void *alloc, char *file, int line)
  320. {
  321. MemHead *mem, *par;
  322. DABNAME("aug_free");
  323. if(!alloc)
  324. aug_abort(file, line, "Attempt to free a NULL pointer");
  325. DAB("Freeing %08lx [+%d %s]", (unsigned long)alloc, line, file);
  326. mem = MEM_CROWN(alloc);
  327. MEM_CHECK(mem, "alloc to free");
  328. par = mem->m.parent;
  329. MEM_CHECK(par, "parent in free");
  330. if(par)
  331. {
  332. if(par->m.sibling == mem)
  333. par->m.sibling = mem->m.sibling;
  334. else
  335. par->m.child = mem->m.sibling;
  336. }
  337. if(mem->m.sibling)
  338. {
  339. mem->m.sibling->m.parent = par;
  340. mem->m.sibling = 0;
  341. }
  342. mem_free(mem);
  343. }
  344. augExport void aug_foster_loc(void *alloc, void *parent, char *file, int line)
  345. {
  346. MemHead *mem, *fpar, *ppar, *sib;
  347. DABNAME("aug_foster");
  348. DAB("Foster %08lx to %08lx [+%d %s]",
  349. alloc, parent, line, file);
  350. if(!alloc)
  351. aug_abort(file, line, "Attempt to foster a NULL pointer");
  352. mem = MEM_CROWN(alloc);
  353. MEM_CHECK(mem, "alloc to foster");
  354. if(parent)
  355. {
  356. fpar = MEM_CROWN(parent);
  357. MEM_CHECK(fpar, "foster parent");
  358. }
  359. else
  360. fpar = 0;
  361. ppar = mem->m.parent; MEM_CHECK(ppar, "prior parent");
  362. sib = mem->m.sibling; MEM_CHECK(ppar, "sibling in foster");
  363. if(fpar == ppar)
  364. {
  365. DABTRACE("No change in parent (%08lx)", (unsigned long)fpar);
  366. return;
  367. }
  368. if(mem == fpar)
  369. aug_abort(file, line, "Attempt to adopt self");
  370. /*
  371. ** Check for incest - isnew parent actually our child?
  372. */
  373. if(mem_find(mem->m.child, fpar))
  374. aug_abort(file, line, "Attempt to adopt a parent");
  375. /*
  376. ** Leave home.
  377. */
  378. if(!ppar)
  379. {
  380. DABBULK("Leaving orphanage");
  381. if(mem->m.sibling)
  382. mem->m.sibling->m.parent = 0;
  383. }
  384. else if(ppar->m.sibling == mem)
  385. {
  386. DABBULK("Older child");
  387. ppar->m.sibling = mem->m.sibling;
  388. if(ppar->m.sibling)
  389. ppar->m.sibling->m.parent = ppar;
  390. }
  391. else
  392. {
  393. DABBULK("Youngest child");
  394. ppar->m.child = mem->m.sibling;
  395. if(ppar->m.child)
  396. ppar->m.child->m.parent = ppar;
  397. }
  398. /*
  399. ** Find new home.
  400. */
  401. mem->m.parent = fpar;
  402. if(fpar)
  403. {
  404. mem->m.sibling = fpar->m.child;
  405. fpar->m.child = mem;
  406. if(mem->m.sibling)
  407. mem->m.sibling->m.parent = mem;
  408. }
  409. else
  410. mem->m.sibling = 0;
  411. }
  412. augExport char *aug_strdup_loc(char *str, void *parent, char *file, int line)
  413. {
  414. char *new;
  415. size_t size;
  416. DABNAME("aug_strdup");
  417. if(!str)
  418. aug_abort(file, line, "Attempt to duplicate a NULL string");
  419. size = strlen(str)+1;
  420. DAB("string length %lu [+%d %s]", (unsigned long)size, line, file);
  421. new = mem_alloc(size, parent, file, line);
  422. DABL(80)("size %lu with header, caller mem at %08lx",
  423. MEM_CROWN(new)->m.end - (char *)MEM_CROWN(new),
  424. (unsigned long)new);
  425. strcpy(new, str);
  426. return new;
  427. }
  428. augExport char **aug_vecdup_loc(char **vec, void *parent, char *file, int line)
  429. {
  430. char **nv, **v, *c;
  431. size_t size;
  432. int vsize;
  433. DABNAME("aug_vecdup");
  434. if(!vec)
  435. aug_abort(file, line, "Attempt to duplicate a NULL vector");
  436. size = 0;
  437. for(v = vec; *v; v++)
  438. size += strlen(*v) + 1;
  439. vsize = v - vec;
  440. DABL(80)("%d elements, total string size %d", vsize, size);
  441. vsize++;
  442. nv = (char **)mem_alloc(vsize * sizeof *v + size, parent, file, line);
  443. c = (char *)(nv + vsize);
  444. for(v = nv; *vec; v++, vec++)
  445. {
  446. strcpy(c, *vec);
  447. *v = c;
  448. c += strlen(c) + 1;
  449. }
  450. *v = 0;
  451. return nv;
  452. }
  453. #ifdef TEST
  454. static void nomem(size_t size, char *func, char *file, int line)
  455. {
  456. fprintf(stderr, "\nNOMEM on %lu bytes via %s, called from %s line %d\n",
  457. (unsigned long)size, func, file, line);
  458. /*
  459. ** Normally would exit from here, but might as well test the
  460. ** default trap.
  461. */
  462. return;
  463. }
  464. main(int argc, char **argv)
  465. {
  466. int i;
  467. void *par;
  468. char *mem, *m, **v;
  469. aug_setmodule(argv[0]);
  470. printf("<MemHead size %lu> should equal <struct MemHead %lu>\n",
  471. sizeof (MemHead), sizeof (struct MemHead));
  472. par = aug_alloc(20, 0);
  473. for(i = 0; i < 20; i++)
  474. {
  475. if(i == 10)
  476. mem = aug_strdup("Hello, world\n", par);
  477. else
  478. (void)aug_alloc(3000, par);
  479. }
  480. mem = aug_realloc(10000, mem);
  481. for(i = 0; i < 20; i++)
  482. {
  483. if(i == 10)
  484. m = aug_strdup("Hello, world\n", mem);
  485. else
  486. (void)aug_alloc(3000, par);
  487. }
  488. v = aug_vecdup(argv, par);
  489. printf("Program args:");
  490. while(*v)
  491. {
  492. printf(" %s", *v++);
  493. fflush(stdout);
  494. }
  495. printf("\n");
  496. aug_foster(m, par);
  497. if(argc > 1)
  498. {
  499. printf("Checking anti-incest test ... this should abort\n");
  500. aug_foster(par, mem);
  501. }
  502. for(i = 0; i < 20; i++)
  503. {
  504. if(i == 10)
  505. m = aug_strdup("Hello, world\n", mem);
  506. else
  507. (void)aug_alloc(3000, mem);
  508. }
  509. mem = aug_realloc(10000, mem);
  510. aug_foster(m, par);
  511. aug_free(mem);
  512. printf("If you can read this, the test completed ok\n");
  513. printf("Now testing NOMEM func - this should abort after a while ... ");
  514. fflush(stdout);
  515. aug_set_nomem_func(nomem);
  516. while(m = aug_alloc(128*1024, par))
  517. continue;
  518. /* Should never get to here */
  519. aug_free(par);
  520. aug_exit(augEXIT_YES);
  521. }
  522. #endif