2
0

aug_alloc.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  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. }
  112. /*
  113. ** Calculate the MemHead address given an aug_alloc() pointer.
  114. */
  115. #define MEM_CROWN(alloc) ((MemHead *)(((char *)alloc) - sizeof (MemHead)))
  116. #define MEM_DECAPITATE(mem) ((void *)(((char *)mem) + sizeof (MemHead)))
  117. static MemMagic mem_magic = MEM_MAGIC_BOUND;
  118. #define MEM_TAIL(p) (memcmp((p)->m.end,(char*)&mem_magic,sizeof mem_magic)==0)
  119. #define MEM_CHECK(p,w) ((p) && \
  120. ((p)->m.magic != MEM_MAGIC_BOUND || !MEM_TAIL(p)) && \
  121. mem_bad((p),(w),file,line))
  122. /* Initialize stats structure with estimated overhead */
  123. static augAllocStats mem_stats = {sizeof (MemHead) + sizeof (MemMagic) + 8, 0};
  124. static augNoMemFunc *mem_nomem_func = 0;
  125. static void mem_nomem(size_t size, char *func, char *file, int line)
  126. {
  127. static augBool active = augFALSE;
  128. char *module;
  129. if(!func)
  130. func = "unknown function";
  131. if(active)
  132. fprintf(stderr, "\r\n\nPANIC: nomem bounce\r\n\n");
  133. else
  134. {
  135. active = augTRUE;
  136. if(mem_nomem_func)
  137. (*mem_nomem_func)(size, func, file, line);
  138. }
  139. fprintf(stderr, "\r\n\n");
  140. module = aug_module();
  141. if(module && *module)
  142. fprintf(stderr, "FATAL in %s: ", module);
  143. else
  144. fprintf(stderr, "FATAL: ");
  145. fprintf(stderr, "%s failure allocating %lu bytes ", func, size);
  146. if(file && *file)
  147. fprintf(stderr, "from +%d %s \r\n", line, file);
  148. else
  149. fprintf(stderr, "(unknown location) \r\n");
  150. fprintf(stderr, " Current allocations: %10lu \r\n",
  151. (mem_stats.alloc_ops - mem_stats.free_ops));
  152. fprintf(stderr, " Total allocations: %10lu \r\n",
  153. mem_stats.alloc_ops);
  154. fprintf(stderr, " Total reallocations: %10lu \r\n",
  155. mem_stats.realloc_ops);
  156. fprintf(stderr, " Total frees: %10lu \r\n",
  157. mem_stats.free_ops);
  158. fprintf(stderr, "Estimated total heap use (KBytes): %10lu \r\n",
  159. (mem_stats.current_bytes_allocated +
  160. (mem_stats.alloc_ops - mem_stats.free_ops) *
  161. mem_stats.estimated_overhead_per_alloc + 512)/1024);
  162. fprintf(stderr, "\n");
  163. aug_exit(augEXIT_NOMEM);
  164. }
  165. static void *mem_alloc(size_t size, void *parent, char *file, int line)
  166. {
  167. MemHead *mem, *par;
  168. DABNAME("mem_alloc");
  169. if(parent)
  170. {
  171. par = MEM_CROWN(parent);
  172. MEM_CHECK(par, "parent");
  173. MEM_CHECK(par->m.child, "sibling");
  174. MEM_CHECK(par->m.sibling, "uncle");
  175. }
  176. else
  177. par = 0;
  178. mem_stats.current_bytes_allocated += size;
  179. mem_stats.alloc_ops++;
  180. /* Adjust for overhead */
  181. size += sizeof (MemHead);
  182. mem = malloc(size + sizeof (MemMagic));
  183. if(!mem)
  184. mem_nomem(size, "aug_alloc", file, line);
  185. if(DABLEVEL(DAB_STD))
  186. {
  187. unsigned long *p;
  188. p = (unsigned long *)mem;
  189. while((char *)p <= (char *)mem + size)
  190. *p++ = MEM_MAGIC_FILL;
  191. }
  192. mem->m.magic = MEM_MAGIC_BOUND;
  193. mem->m.file = file;
  194. mem->m.line = line;
  195. mem->m.end = (char *)mem + size;
  196. mem->m.options = 0;
  197. mem->m.child = 0;
  198. mem->m.parent = par;
  199. if(par)
  200. {
  201. if(mem->m.sibling = par->m.child)
  202. mem->m.sibling->m.parent = mem;
  203. par->m.child = mem;
  204. }
  205. else
  206. mem->m.sibling = 0;
  207. memcpy(mem->m.end, (char *)&mem_magic, sizeof mem_magic);
  208. return MEM_DECAPITATE(mem);
  209. }
  210. static void mem_free(MemHead *mem)
  211. {
  212. size_t size;
  213. DABNAME("mem_free");
  214. while(mem)
  215. {
  216. MemHead *next = mem->m.sibling;
  217. if(mem->m.child)
  218. mem_free(mem->m.child);
  219. size = (char *)mem->m.end - (char *)mem;
  220. size -= sizeof (MemHead) + sizeof (MemMagic);
  221. mem_stats.current_bytes_allocated -= size;
  222. mem_stats.free_ops++;
  223. if(DABLEVEL(DAB_STD))
  224. {
  225. unsigned long *p = (unsigned long *)(mem+1);
  226. while((char *)p <= mem->m.end)
  227. *p++ = MEM_MAGIC_FILL;
  228. p = (unsigned long *)mem;
  229. while(p < (unsigned long *)(mem+1))
  230. *p++ = MEM_MAGIC_FILL;
  231. }
  232. free(mem);
  233. mem = next;
  234. }
  235. }
  236. static augBool mem_find(MemHead *mem, MemHead *p)
  237. {
  238. while(mem)
  239. {
  240. MemHead *next;
  241. if(mem == p)
  242. return augTRUE;
  243. next = mem->m.sibling;
  244. if(mem->m.child)
  245. if(mem_find(mem->m.child, p))
  246. return augTRUE;
  247. mem = next;
  248. }
  249. return augFALSE;
  250. }
  251. augExport augNoMemFunc *aug_set_nomem_func(augNoMemFunc *new_func)
  252. {
  253. augNoMemFunc *old = mem_nomem_func;
  254. DABNAME("aug_set_nomem_func");
  255. mem_nomem_func = new_func;
  256. DABTRACE("New nomem func %08lx, previous %08lx",
  257. (unsigned long)mem_nomem_func, (unsigned long)old);
  258. return old;
  259. }
  260. augExport augAllocStats *aug_alloc_stats(void)
  261. {
  262. return &mem_stats;
  263. }
  264. augExport void *aug_alloc_loc(size_t size, void *parent, char *file, int line)
  265. {
  266. void *alloc;
  267. DABNAME("aug_alloc");
  268. DAB("size %lu, parent %08lx [+%d %s]",
  269. (unsigned long)size, (unsigned long)parent, line, file);
  270. alloc = mem_alloc(size, parent, file, line);
  271. DABL(80)("size %lu with header, caller mem at %08lx",
  272. MEM_CROWN(alloc)->m.end - (char *)MEM_CROWN(alloc),
  273. (unsigned long)alloc);
  274. return alloc;
  275. }
  276. augExport void *aug_realloc_loc(size_t size, void *prev, char *file, int line)
  277. {
  278. void *alloc;
  279. size_t prev_size;
  280. MemHead *mem, *par, *kid, *sib, *new;
  281. DABNAME("aug_realloc");
  282. if(!prev)
  283. aug_abort(file, line, "Attempt to realloc a NULL pointer");
  284. mem = MEM_CROWN(prev);
  285. MEM_CHECK(mem, "previous alloc");
  286. par = mem->m.parent; MEM_CHECK(par, "realloc parent");
  287. kid = mem->m.child; MEM_CHECK(kid, "realloc child");
  288. sib = mem->m.sibling; MEM_CHECK(sib, "realloc sibling");
  289. prev_size = (mem->m.end - (char *)mem) - sizeof (MemHead);
  290. DAB("prior size %lu, new %lu [+%d %s]",
  291. (unsigned long)prev_size, (unsigned long)size,
  292. line, file);
  293. DABL(80)("prior mem %08lx", (unsigned long)mem);
  294. mem_stats.current_bytes_allocated += size - prev_size;
  295. mem_stats.realloc_ops++;
  296. size += sizeof (MemHead);
  297. new = realloc(mem, size + sizeof (MemMagic));
  298. if(!new)
  299. mem_nomem(size, "aug_realloc", file, line);
  300. new->m.end = (char *)new + size;
  301. memcpy(new->m.end, (char *)&mem_magic, sizeof mem_magic);
  302. if(par)
  303. {
  304. if(par->m.sibling == mem)
  305. par->m.sibling = new;
  306. else
  307. par->m.child = new;
  308. }
  309. if(kid)
  310. kid->m.parent = new;
  311. if(sib)
  312. sib->m.parent = new;
  313. alloc = MEM_DECAPITATE(new);
  314. DABL(80)("size %lu with header, caller mem at %08lx",
  315. new->m.end - (char *)new, (unsigned long)alloc);
  316. return alloc;
  317. }
  318. augExport void aug_free_loc(void *alloc, char *file, int line)
  319. {
  320. MemHead *mem, *par;
  321. DABNAME("aug_free");
  322. if(!alloc)
  323. aug_abort(file, line, "Attempt to free a NULL pointer");
  324. DAB("Freeing %08lx [+%d %s]", (unsigned long)alloc, line, file);
  325. mem = MEM_CROWN(alloc);
  326. MEM_CHECK(mem, "alloc to free");
  327. par = mem->m.parent;
  328. MEM_CHECK(par, "parent in free");
  329. if(par)
  330. {
  331. if(par->m.sibling == mem)
  332. par->m.sibling = mem->m.sibling;
  333. else
  334. par->m.child = mem->m.sibling;
  335. }
  336. if(mem->m.sibling)
  337. {
  338. mem->m.sibling->m.parent = par;
  339. mem->m.sibling = 0;
  340. }
  341. mem_free(mem);
  342. }
  343. augExport void aug_foster_loc(void *alloc, void *parent, char *file, int line)
  344. {
  345. MemHead *mem, *fpar, *ppar, *sib;
  346. DABNAME("aug_foster");
  347. DAB("Foster %08lx to %08lx [+%d %s]",
  348. alloc, parent, line, file);
  349. if(!alloc)
  350. aug_abort(file, line, "Attempt to foster a NULL pointer");
  351. mem = MEM_CROWN(alloc);
  352. MEM_CHECK(mem, "alloc to foster");
  353. if(parent)
  354. {
  355. fpar = MEM_CROWN(parent);
  356. MEM_CHECK(fpar, "foster parent");
  357. }
  358. else
  359. fpar = 0;
  360. ppar = mem->m.parent; MEM_CHECK(ppar, "prior parent");
  361. sib = mem->m.sibling; MEM_CHECK(ppar, "sibling in foster");
  362. if(fpar == ppar)
  363. {
  364. DABTRACE("No change in parent (%08lx)", (unsigned long)fpar);
  365. return;
  366. }
  367. if(mem == fpar)
  368. aug_abort(file, line, "Attempt to adopt self");
  369. /*
  370. ** Check for incest - isnew parent actually our child?
  371. */
  372. if(mem_find(mem->m.child, fpar))
  373. aug_abort(file, line, "Attempt to adopt a parent");
  374. /*
  375. ** Leave home.
  376. */
  377. if(!ppar)
  378. {
  379. DABBULK("Leaving orphanage");
  380. if(mem->m.sibling)
  381. mem->m.sibling->m.parent = 0;
  382. }
  383. else if(ppar->m.sibling == mem)
  384. {
  385. DABBULK("Older child");
  386. ppar->m.sibling = mem->m.sibling;
  387. if(ppar->m.sibling)
  388. ppar->m.sibling->m.parent = ppar;
  389. }
  390. else
  391. {
  392. DABBULK("Youngest child");
  393. ppar->m.child = mem->m.sibling;
  394. if(ppar->m.child)
  395. ppar->m.child->m.parent = ppar;
  396. }
  397. /*
  398. ** Find new home.
  399. */
  400. mem->m.parent = fpar;
  401. if(fpar)
  402. {
  403. mem->m.sibling = fpar->m.child;
  404. fpar->m.child = mem;
  405. if(mem->m.sibling)
  406. mem->m.sibling->m.parent = mem;
  407. }
  408. else
  409. mem->m.sibling = 0;
  410. }
  411. augExport char *aug_strdup_loc(char *str, void *parent, char *file, int line)
  412. {
  413. char *new;
  414. size_t size;
  415. DABNAME("aug_strdup");
  416. if(!str)
  417. aug_abort(file, line, "Attempt to duplicate a NULL string");
  418. size = strlen(str)+1;
  419. DAB("string length %lu [+%d %s]", (unsigned long)size, line, file);
  420. new = mem_alloc(size, parent, file, line);
  421. DABL(80)("size %lu with header, caller mem at %08lx",
  422. MEM_CROWN(new)->m.end - (char *)MEM_CROWN(new),
  423. (unsigned long)new);
  424. strcpy(new, str);
  425. return new;
  426. }
  427. augExport char **aug_vecdup_loc(char **vec, void *parent, char *file, int line)
  428. {
  429. char **nv, **v, *c;
  430. size_t size;
  431. int vsize;
  432. DABNAME("aug_vecdup");
  433. if(!vec)
  434. aug_abort(file, line, "Attempt to duplicate a NULL vector");
  435. size = 0;
  436. for(v = vec; *v; v++)
  437. size += strlen(*v) + 1;
  438. vsize = v - vec;
  439. DABL(80)("%d elements, total string size %d", vsize, size);
  440. vsize++;
  441. nv = (char **)mem_alloc(vsize * sizeof *v + size, parent, file, line);
  442. c = (char *)(nv + vsize);
  443. for(v = nv; *vec; v++, vec++)
  444. {
  445. strcpy(c, *vec);
  446. *v = c;
  447. c += strlen(c) + 1;
  448. }
  449. *v = 0;
  450. return nv;
  451. }
  452. #ifdef TEST
  453. static void nomem(size_t size, char *func, char *file, int line)
  454. {
  455. fprintf(stderr, "\nNOMEM on %lu bytes via %s, called from %s line %d\n",
  456. (unsigned long)size, func, file, line);
  457. /*
  458. ** Normally would exit from here, but might as well test the
  459. ** default trap.
  460. */
  461. return;
  462. }
  463. main(int argc, char **argv)
  464. {
  465. int i;
  466. void *par;
  467. char *mem, *m, **v;
  468. aug_setmodule(argv[0]);
  469. printf("<MemHead size %lu> should equal <struct MemHead %lu>\n",
  470. sizeof (MemHead), sizeof (struct MemHead));
  471. par = aug_alloc(20, 0);
  472. for(i = 0; i < 20; i++)
  473. {
  474. if(i == 10)
  475. mem = aug_strdup("Hello, world\n", par);
  476. else
  477. (void)aug_alloc(3000, par);
  478. }
  479. mem = aug_realloc(10000, mem);
  480. for(i = 0; i < 20; i++)
  481. {
  482. if(i == 10)
  483. m = aug_strdup("Hello, world\n", mem);
  484. else
  485. (void)aug_alloc(3000, par);
  486. }
  487. v = aug_vecdup(argv, par);
  488. printf("Program args:");
  489. while(*v)
  490. {
  491. printf(" %s", *v++);
  492. fflush(stdout);
  493. }
  494. printf("\n");
  495. aug_foster(m, par);
  496. if(argc > 1)
  497. {
  498. printf("Checking anti-incest test ... this should abort\n");
  499. aug_foster(par, mem);
  500. }
  501. for(i = 0; i < 20; i++)
  502. {
  503. if(i == 10)
  504. m = aug_strdup("Hello, world\n", mem);
  505. else
  506. (void)aug_alloc(3000, mem);
  507. }
  508. mem = aug_realloc(10000, mem);
  509. aug_foster(m, par);
  510. aug_free(mem);
  511. printf("If you can read this, the test completed ok\n");
  512. printf("Now testing NOMEM func - this should abort after a while ... ");
  513. fflush(stdout);
  514. aug_set_nomem_func(nomem);
  515. while(m = aug_alloc(128*1024, par))
  516. continue;
  517. /* Should never get to here */
  518. aug_free(par);
  519. aug_exit(augEXIT_YES);
  520. }
  521. #endif