home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume27 / leak / part01 < prev    next >
Encoding:
Text File  |  1993-10-11  |  12.1 KB  |  474 lines

  1. Newsgroups: comp.sources.unix
  2. From: pefv700@hermes.chpc.utexas.edu (Christopher Phillips)
  3. Subject: v27i066: leak - quick and dirty code to find memory leaks, Part01/01
  4. Message-id: <1.750376543.23906@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: pefv700@hermes.chpc.utexas.edu (Christopher Phillips)
  9. Posting-Number: Volume 27, Issue 66
  10. Archive-Name: leak/part01
  11.  
  12. What leak does:
  13.  
  14.     * Logs all malloc/realloc/free calls to dbm files
  15.       with filename and line number
  16.     * Complains about reallocing/freeing addresses not
  17.       the result of a prior malloc/realloc
  18.     * Dumps unfreed addresses upon request
  19.  
  20. How to use leak:
  21.  
  22.     * #include "leak.h" in all source files that call
  23.       malloc/realloc/free
  24.     * recompile
  25.     * run program
  26.     * run leakdump
  27.  
  28. pefv700@hermes.chpc.utexas.edu (Christopher Phillips)
  29.  
  30. #! /bin/sh
  31. # This is a shell archive.  Remove anything before this line, then unpack
  32. # it by saving it into a file and typing "sh file".  To overwrite existing
  33. # files, type "sh file -c".  You can also feed this as standard input via
  34. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  35. # will see the following message at the end:
  36. #        "End of shell archive."
  37. # Contents:  leak leak/Makefile leak/README leak/leak.c leak/leak.h
  38. #   leak/leakdump.c leak/leaktest.c
  39. # Wrapped by pefv700@hermes on Mon Oct 11 11:39:31 1993
  40. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  41. if test ! -d 'leak' ; then
  42.     echo shar: Creating directory \"'leak'\"
  43.     mkdir 'leak'
  44. fi
  45. if test -f 'leak/Makefile' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'leak/Makefile'\"
  47. else
  48. echo shar: Extracting \"'leak/Makefile'\" \(293 characters\)
  49. sed "s/^X//" >'leak/Makefile' <<'END_OF_FILE'
  50. Xall: test leaktest leakdump
  51. X
  52. Xleaktest: leaktest.o leak.o
  53. X    $(CC) -o $@ leaktest.o leak.o
  54. X
  55. Xleakdump: leakdump.o leak.o
  56. X    $(CC) -o $@ leakdump.o leak.o
  57. X
  58. Xtest: leaktest leakdump
  59. X    @echo Running leaktest
  60. X    @leaktest
  61. X    @echo Running leakdump
  62. X    @leakdump
  63. X
  64. Xclean:
  65. X    -rm -f *.o leaktest leakdump *.dir *.pag
  66. END_OF_FILE
  67. if test 293 -ne `wc -c <'leak/Makefile'`; then
  68.     echo shar: \"'leak/Makefile'\" unpacked with wrong size!
  69. fi
  70. # end of 'leak/Makefile'
  71. fi
  72. if test -f 'leak/README' -a "${1}" != "-c" ; then 
  73.   echo shar: Will not clobber existing file \"'leak/README'\"
  74. else
  75. echo shar: Extracting \"'leak/README'\" \(1545 characters\)
  76. sed "s/^X//" >'leak/README' <<'END_OF_FILE'
  77. X
  78. XLEAK - Quick and dirty code to find memory leaks
  79. X       (Requires ANSI C and ndbm)
  80. X
  81. XWhat leak does:
  82. X
  83. X    * Logs all malloc/realloc/free calls to dbm files
  84. X      with filename and line number
  85. X    * Complains about reallocing/freeing addresses not
  86. X      the result of a prior malloc/realloc
  87. X    * Dumps unfreed addresses upon request
  88. X
  89. XHow to use leak:
  90. X
  91. X    * #include "leak.h" in all source files that call
  92. X      malloc/realloc/free
  93. X    * recompile
  94. X    * run program
  95. X    * run leakdump
  96. X
  97. XThat's all there is to it.  For example:
  98. X
  99. X% make
  100. Xcc -c leaktest.c -o leaktest.o
  101. Xcc -c leak.c -o leak.o
  102. Xcc -o leaktest leaktest.o leak.o
  103. Xcc -c leakdump.c -o leakdump.o
  104. Xcc -o leakdump leakdump.o leak.o
  105. X% leaktest
  106. X% leakdump
  107. XNonfreed blocks:
  108. XAddress         Size    Line    File
  109. X------------------------------------
  110. X140004110       40      16      leaktest.c
  111. X%
  112. X
  113. XNotes:
  114. X    * The dbm files are not automatically deleted
  115. X    * When using libraries that use malloc/realloc/free
  116. X      but for which you don't have source, don't have leak
  117. X      log the use of this memory.  For example, if libMRF.a
  118. X      mallocs memory that you should free, don't have leak
  119. X      log the free or it will complain.
  120. X    * If you have library functions whose main function
  121. X      is to call malloc/realloc, it is usually more relevant
  122. X      to know which function called the library function.
  123. X      Unfortunately, determining that information is
  124. X      platform-specific.
  125. X    * All malloced/realloced memory should be explicitly
  126. X      freed or it will show up in the dump.
  127. X
  128. X
  129. XChris
  130. X
  131. X-----------------------
  132. XChristopher G. Phillips
  133. Xpefv700@utpe.pe.utexas.edu
  134. END_OF_FILE
  135. if test 1545 -ne `wc -c <'leak/README'`; then
  136.     echo shar: \"'leak/README'\" unpacked with wrong size!
  137. fi
  138. # end of 'leak/README'
  139. fi
  140. if test -f 'leak/leak.c' -a "${1}" != "-c" ; then 
  141.   echo shar: Will not clobber existing file \"'leak/leak.c'\"
  142. else
  143. echo shar: Extracting \"'leak/leak.c'\" \(3949 characters\)
  144. sed "s/^X//" >'leak/leak.c' <<'END_OF_FILE'
  145. X/*
  146. X *                 Author:  Christopher G. Phillips
  147. X *              Copyright (C) 1993 All Rights Reserved
  148. X *
  149. X *                              NOTICE
  150. X *
  151. X * Permission to use, copy, modify, and distribute this software and
  152. X * its documentation for any purpose and without fee is hereby granted
  153. X * provided that the above copyright notice appear in all copies and
  154. X * that both the copyright notice and this permission notice appear in
  155. X * supporting documentation.
  156. X *
  157. X * The author makes no representations about the suitability of this
  158. X * software for any purpose.  This software is provided ``as is''
  159. X * without express or implied warranty.
  160. X */
  161. X
  162. X#include <stdio.h>
  163. X#include <stdlib.h>
  164. X#include <sys/types.h>
  165. X#include <sys/stat.h>
  166. X#include <string.h>
  167. X#include <unistd.h>
  168. X#include <fcntl.h>
  169. X#include "leak.h"
  170. X
  171. X#define FILE_DBMFILENAME    "filedbm"
  172. X#define MEMORY_DBMFILENAME    "memdbm"
  173. X
  174. Xvoid    *_ptr;
  175. X
  176. Xtypedef char    *DPTR;
  177. X
  178. Xstatic DBM    *filedbm = NULL;
  179. Xstatic DBM    *memdbm = NULL;
  180. Xstatic int    nextfile = -1;
  181. X
  182. Xstruct memdata {
  183. X    size_t    size;
  184. X    int    file;
  185. X    int    line;
  186. X};
  187. X
  188. Xstatic void
  189. Xopendbmfiles(mode_t mode)
  190. X{
  191. X    if (filedbm == NULL && (filedbm = dbm_open(FILE_DBMFILENAME, mode,
  192. X      S_IRUSR | S_IWUSR)) == NULL
  193. X      || memdbm == NULL && (memdbm = dbm_open(MEMORY_DBMFILENAME, mode,
  194. X      S_IRUSR | S_IWUSR)) == NULL) {
  195. X        perror("dbm_open");
  196. X        exit(1);
  197. X    }
  198. X}
  199. X
  200. Xstatic int
  201. Xfile2int(const char *file)
  202. X{
  203. X    datum    key, data;
  204. X
  205. X    key.dptr = (DPTR)file;
  206. X    key.dsize = strlen(file) + 1;
  207. X    data = dbm_fetch(filedbm, key);
  208. X    if (data.dptr) {
  209. X        int    i;
  210. X
  211. X        (void)memcpy(&i, data.dptr, sizeof i);
  212. X        return i;
  213. X    } else {
  214. X        ++nextfile;
  215. X        data.dptr = (DPTR)&nextfile;
  216. X        data.dsize = sizeof nextfile;
  217. X        if (dbm_store(filedbm, key, data, DBM_INSERT) < 0) {
  218. X            perror("dbm_store");
  219. X            exit(1);
  220. X        }
  221. X        return nextfile;
  222. X    }
  223. X}
  224. X
  225. Xstatic char *
  226. Xint2file(int file)
  227. X{
  228. X    datum    key, data;
  229. X    int    i;
  230. X
  231. X    for (key = dbm_firstkey(filedbm); key.dptr;
  232. X      key = dbm_nextkey(filedbm)) {
  233. X        data = dbm_fetch(filedbm, key);
  234. X        if (data.dptr == NULL) {
  235. X            perror("dbm_fetch");
  236. X            continue;
  237. X        }
  238. X        (void)memcpy(&i, data.dptr, sizeof i);
  239. X        if (i == file)
  240. X            return key.dptr;
  241. X    }
  242. X    return "???";
  243. X}
  244. X
  245. Xvoid
  246. X_dbinsert(void *p, size_t size, const char *file, int line, int mode)
  247. X{
  248. X    struct memdata    md;
  249. X    datum        key, data;
  250. X
  251. X    if (!filedbm || !memdbm)
  252. X        opendbmfiles(O_RDWR | O_CREAT | O_TRUNC);
  253. X
  254. X    md.file = file2int(file);
  255. X
  256. X    md.size = size;
  257. X    md.line = line;
  258. X    key.dptr = (DPTR)&p;
  259. X    key.dsize = sizeof p;
  260. X    data.dptr = (DPTR)&md;
  261. X    data.dsize = sizeof md;
  262. X
  263. X    if (dbm_store(memdbm, key, data, DBM_INSERT) == -1) {
  264. X        perror("dbm_store");
  265. X        exit(1);
  266. X    }
  267. X}
  268. X
  269. Xvoid
  270. X_dbdelete(void *p, const char *file, int line)
  271. X{
  272. X    struct memdata    md;
  273. X    datum        key, data;
  274. X
  275. X    key.dptr = (DPTR)&p;
  276. X    key.dsize = sizeof p;
  277. X
  278. X    if (memdbm == NULL) {
  279. X        fprintf(stderr, "free before malloc from \"%s\", line %d\n",
  280. X          file, line);
  281. X        exit(1);
  282. X    } else if (dbm_delete(memdbm, key) == -1) {
  283. X        fprintf(stderr,
  284. X          "free unmalloced pointer %p from \"%s\", line %d\n", p, file,
  285. X          line);
  286. X        exit(1);
  287. X    }
  288. X}
  289. X
  290. Xvoid
  291. X_dbdump(mode_t mode)
  292. X{
  293. X    struct memdata    *mdp;
  294. X    datum        key, data;
  295. X    int        do_title = 1;
  296. X
  297. X    if (!filedbm || !memdbm)
  298. X        opendbmfiles(mode);
  299. X
  300. X    for (key = dbm_firstkey(memdbm); key.dptr; key = dbm_nextkey(memdbm)) {
  301. X        data = dbm_fetch(memdbm, key);
  302. X        if (data.dptr == NULL) {
  303. X            perror("dbm_fetch");
  304. X            continue;
  305. X        }
  306. X        if (do_title) {
  307. X            int    i;
  308. X
  309. X            printf("Nonfreed blocks:\n");
  310. X            printf("Address \tSize\tLine\tFile\n");
  311. X            for (i = 0; i < 36; i++)
  312. X                putchar('-');
  313. X            putchar('\n');
  314. X            do_title = 0;
  315. X        }
  316. X        mdp = (struct memdata *)data.dptr;
  317. X#ifndef sun
  318. X        printf("%08p\t%d\t%d\t%s\n", *(void **)key.dptr,
  319. X#else
  320. X        printf("%08x\t%d\t%d\t%s\n", (int)*(void **)key.dptr,
  321. X#endif
  322. X          mdp->size, mdp->line, int2file(mdp->file));
  323. X    }
  324. X}
  325. X
  326. X#if 0
  327. Xvoid
  328. Xexit(int status)
  329. X{
  330. X    _dbdump(O_RDONLY);
  331. X    (void)dbm_close(memdbm);
  332. X    (void)dbm_close(filedbm);
  333. X    (void)remove("memdbm.dir");
  334. X    (void)remove("memdbm.pag");
  335. X    (void)remove("filedbm.dir");
  336. X    (void)remove("filedbm.pag");
  337. X    fflush(NULL);
  338. X    _exit(status);
  339. X}
  340. X#endif
  341. END_OF_FILE
  342. if test 3949 -ne `wc -c <'leak/leak.c'`; then
  343.     echo shar: \"'leak/leak.c'\" unpacked with wrong size!
  344. fi
  345. # end of 'leak/leak.c'
  346. fi
  347. if test -f 'leak/leak.h' -a "${1}" != "-c" ; then 
  348.   echo shar: Will not clobber existing file \"'leak/leak.h'\"
  349. else
  350. echo shar: Extracting \"'leak/leak.h'\" \(1343 characters\)
  351. sed "s/^X//" >'leak/leak.h' <<'END_OF_FILE'
  352. X/*
  353. X *                 Author:  Christopher G. Phillips
  354. X *              Copyright (C) 1993 All Rights Reserved
  355. X *
  356. X *                              NOTICE
  357. X *
  358. X * Permission to use, copy, modify, and distribute this software and
  359. X * its documentation for any purpose and without fee is hereby granted
  360. X * provided that the above copyright notice appear in all copies and
  361. X * that both the copyright notice and this permission notice appear in
  362. X * supporting documentation.
  363. X *
  364. X * The author makes no representations about the suitability of this
  365. X * software for any purpose.  This software is provided ``as is''
  366. X * without express or implied warranty.
  367. X */
  368. X
  369. X#ifndef H_LEAK
  370. X#define H_LEAK
  371. X
  372. X#include <sys/types.h>
  373. X#include <stdlib.h>
  374. X#include <ndbm.h>
  375. X
  376. Xextern void    *_ptr;
  377. Xextern void    _dbinsert(void *, size_t, const char *, int, int);
  378. Xextern void    _dbdelete(void *, const char *, int);
  379. X
  380. X#define malloc(s) \
  381. X  (_ptr = malloc(s), _dbinsert(_ptr, s, __FILE__, __LINE__, DBM_INSERT), _ptr)
  382. X
  383. X#define realloc(p, s) \
  384. X    ((_ptr = realloc(p, s)), \
  385. X    ((_ptr && _ptr == p) \
  386. X      ? _dbinsert(_ptr, s, __FILE__, __LINE__, DBM_REPLACE), 0 : 0), \
  387. X    (_ptr ? \
  388. X     (p ? _dbdelete(p, __FILE__, __LINE__), 0 : 0), \
  389. X    _dbinsert(_ptr, s, __FILE__, __LINE__, DBM_INSERT), 0 : 0), \
  390. X    _ptr)
  391. X
  392. X#define free(p)        (p ? _dbdelete(p, __FILE__, __LINE__), 0 : 0), free(p)
  393. X
  394. X#endif /* H_LEAK */
  395. END_OF_FILE
  396. if test 1343 -ne `wc -c <'leak/leak.h'`; then
  397.     echo shar: \"'leak/leak.h'\" unpacked with wrong size!
  398. fi
  399. # end of 'leak/leak.h'
  400. fi
  401. if test -f 'leak/leakdump.c' -a "${1}" != "-c" ; then 
  402.   echo shar: Will not clobber existing file \"'leak/leakdump.c'\"
  403. else
  404. echo shar: Extracting \"'leak/leakdump.c'\" \(774 characters\)
  405. sed "s/^X//" >'leak/leakdump.c' <<'END_OF_FILE'
  406. X/*
  407. X *                 Author:  Christopher G. Phillips
  408. X *              Copyright (C) 1993 All Rights Reserved
  409. X *
  410. X *                              NOTICE
  411. X *
  412. X * Permission to use, copy, modify, and distribute this software and
  413. X * its documentation for any purpose and without fee is hereby granted
  414. X * provided that the above copyright notice appear in all copies and
  415. X * that both the copyright notice and this permission notice appear in
  416. X * supporting documentation.
  417. X *
  418. X * The author makes no representations about the suitability of this
  419. X * software for any purpose.  This software is provided ``as is''
  420. X * without express or implied warranty.
  421. X */
  422. X
  423. X#include <stdio.h>
  424. X#include <stdlib.h>
  425. X#include <fcntl.h>
  426. X#include "leak.h"
  427. X
  428. Xint
  429. Xmain(void)
  430. X{
  431. X    _dbdump(O_RDONLY);
  432. X
  433. X    exit(0);
  434. X}
  435. END_OF_FILE
  436. if test 774 -ne `wc -c <'leak/leakdump.c'`; then
  437.     echo shar: \"'leak/leakdump.c'\" unpacked with wrong size!
  438. fi
  439. # end of 'leak/leakdump.c'
  440. fi
  441. if test -f 'leak/leaktest.c' -a "${1}" != "-c" ; then 
  442.   echo shar: Will not clobber existing file \"'leak/leaktest.c'\"
  443. else
  444. echo shar: Extracting \"'leak/leaktest.c'\" \(237 characters\)
  445. sed "s/^X//" >'leak/leaktest.c' <<'END_OF_FILE'
  446. X#include <stdio.h>
  447. X#include <stdlib.h>
  448. X#include <limits.h>
  449. X#include "leak.h"
  450. X
  451. Xint
  452. Xmain(void)
  453. X{
  454. X    void    *p, *q;
  455. X
  456. X    p = malloc(3);
  457. X    free(NULL);
  458. X    if ((q = realloc(p, INT_MAX)) == NULL)
  459. X        free(p);
  460. X    else
  461. X        free(q);
  462. X    p = malloc(40);
  463. X
  464. X    exit(0);
  465. X}
  466. END_OF_FILE
  467. if test 237 -ne `wc -c <'leak/leaktest.c'`; then
  468.     echo shar: \"'leak/leaktest.c'\" unpacked with wrong size!
  469. fi
  470. # end of 'leak/leaktest.c'
  471. fi
  472. echo shar: End of shell archive.
  473. exit 0
  474.