home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / compsrcs / unix / volume18 / malloctr.ace < prev    next >
Encoding:
Internet Message Format  |  1989-03-27  |  67.7 KB

  1. Path: wugate!wucs1!uunet!bbn.com!rsalz
  2. From: rsalz@uunet.uu.net (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v18i066:  Malloc package with tracing
  5. Message-ID: <1624@papaya.bbn.com>
  6. Date: 27 Mar 89 17:43:33 GMT
  7. Lines: 2636
  8. Approved: rsalz@uunet.UU.NET
  9.  
  10. Submitted-by: Mark Brader <msb@sq.sq.com>
  11. Posting-number: Volume 18, Issue 66
  12. Archive-name: malloctrace
  13.  
  14. This package has been put together from a number of different pieces and
  15. I don't have time to edit all the README files together nicely.  Most of
  16. them are just cover notes that came with the different parts.  I believe
  17. all code except my own to have previously been posted to the net and
  18. to be in the public domain.  My code is also in the public domain.
  19.  
  20. What this is is a malloc package with tracing, so you can find where in
  21. your program there is a call to malloc() without a matching free().
  22.  
  23. The malloc part is portable, the tracing will need work to run on
  24. anything other than Sun's.
  25.  
  26. : To unbundle, sh this file
  27. echo x - OVERALL_README 1>&2
  28. cat >OVERALL_README <<'@@@End of OVERALL_README'
  29. This package has been put together from a number of different pieces and
  30. I don't have time to edit all the README files together nicely.  Most of
  31. them are just cover notes that came with the different parts.  I believe
  32. all code except my own to have previously been posted to the net and
  33. to be in the public domain.  My code is also in the public domain.
  34.  
  35. What this is is a malloc package with tracing, so you can find where in
  36. your program there is a call to malloc() without a matching free().
  37.  
  38. This package is written in several separate source files so that a program
  39. won't have to load all of it if it doesn't need it.  However, there may be
  40. cases where a function in the C runtime library calls a malloc() family
  41. function that your program doesn't call, and it will then go to the system
  42. version of the malloc() package for that function.  This causes chaos.
  43.  
  44. You can force a particular function to be loaded from the malloctrace.a
  45. library by putting, e.g., "-u _calloc" on the compile line just before
  46. the library name.  Or you could avoid the problem permanently by editing
  47. the files malloc.h, malloc.c, free.c, calloc.c, init_trace.c, write_trace.c,
  48. and forget.c into one big file.
  49.  
  50. The original malloc package was written by Bill Sebok.  I then added the
  51. tracing, while Arthur David Olson, independently, added some bug fixes
  52. and enhancements.   I then took Olson's version and added my tracing to it.
  53.  
  54. For more details on the tracing see mallck.1 and TRACE_README in this
  55. directory.  README is Sebok's original README.  NEW_VERSION_README is
  56. Olson's cover note.  README.mtest2 and README.mtest3 are cover notes
  57. for two malloc-tester programs (originally called mtest and looptest).
  58. (mtest1, included here without its own README file, is part of Sebok's
  59. package and was originally called tstmalloc).
  60.  
  61. UNPORTABILITY CAVEATS -
  62.  
  63.   The tracing depends on being able to dump one's call stack.  This is
  64. done by code in the file write_trace.c.  It works on our Sun running SunOS
  65. 3.0 or 3.2, but is likely to need rewriting on your machine!
  66.   There are two other things that work on our Sun but aren't portable:
  67. the types "char *", "long", and "unsigned" seem to be inter-assigned
  68. carelessly (I don't have time to delint this, either); and the BSDish
  69. library function bcopy() is used.
  70.   Use at your own risk.
  71.  
  72. Mark Brader, SoftQuad Inc., Toronto, August 25, 1988
  73. { uunet!attcan | linus | decvax | watmath | pyramid } !utzoo!sq!msb
  74. msb@sq.com        decwrl!utcsri!sq!msb
  75. @@@End of OVERALL_README
  76. echo x - README 1>&2
  77. cat >README <<'@@@End of README'
  78. This is the malloc()/free()/realloc()/forget() package used at astrovax.
  79. [Except for the MALLOCTRACE feature -- see ./TRACE_README]
  80.  
  81. It does not have the property of the 4.2 BSD malloc of allocating huge amounts
  82. of excess memory.  Image processing is done here and large malloc requests
  83. are not rare.  It is quite undesirable when one asks for 4.1 megabytes of memory
  84. to have it try to return 8 megabytes and to fail because the process goes over
  85. quota or there is not enough swap space.
  86.  
  87. Also this malloc does not have the property of the 4.1 BSD malloc that a search
  88. for free memory traverses a linked list that covers all previous allocations,
  89. causing thrashing by touching them and thus paging them back into memory.
  90.  
  91. Hopefully this malloc covers the best of both worlds.  There is a fair attempt
  92. at storage compaction, merging freed areas with adjacent free areas and
  93. optionally returning freed areas adjacent to the break back to the system,
  94. thereby shrinking the size of the process.
  95.  
  96. It is also allowable and compatible with this package to obtain memory by the
  97. use of the sbrk() system call.  This memory can be reclaimed and returned to
  98. the malloc arena by the use of the provided forget() function.  This function
  99. is intended to provide the functionality of the Forth FORGET primitive in
  100. an environment that also includes malloc and free.
  101.  
  102. The main disadvantage of this package is a larger storage overhead of 24 bytes
  103. per memory area, due to the fact that each area is linked into two
  104. bi-directional chains.
  105.  
  106. Non-vax users should edit the commented system-dependent parts of Makefile and
  107. malloc.h for the requirements of one's own computer.
  108.  
  109. Bill Sebok            Princeton University, Astrophysics
  110. {allegra,akgua,cbosgd,decvax,ihnp4,noao,philabs,princeton,vax135}!astrovax!wls
  111. @@@End of README
  112. echo x - TRACE_README 1>&2
  113. cat >TRACE_README <<'@@@End of TRACE_README'
  114. The files malloc.c, free.c, realloc.c, and malloc.h have been edited,
  115. and the new files write_trace.c and init_trace.c have been created,
  116. to implement the tracing of calls to malloc, free, and realloc.
  117.  
  118. [WARNING: The implementation is system-dependent.  It works on our SunOS 3.2.]
  119.  
  120. The method is based on that described in the paper:
  121.  
  122.     "A Technique for Finding Storage Allocation Errors in
  123.      C-language Programs", David R. Barach, David H. Taenzer,
  124.      and Robert E. Wells; SIGPLAN Notices, V17#5 (May 1982).
  125.  
  126. All these changes and the associated new files are public domain,
  127. and are not guaranteed.
  128.  
  129. Basically, the functions free and malloc are modified by inserting
  130. calls to the new functions init_trace and write_trace.  Init_trace
  131. is called the first time malloc is called; it opens the output file
  132. named by the environment variable $MALLOCTRACE, or "malloc.out" by
  133. default.  Each call to write_trace then writes to that trace file
  134. a one-line description of the current event, e.g. "malloc of 256 at 5a10a".
  135. It follows this by a traceback of the calling stack with one line for
  136. each stack frame, e.g. "caller 0000210f", and an empty line.
  137.  
  138. The possible events are "malloc" and "realloc-to" to allocate memory,
  139. "free" and "realloc" to free memory.  A call to realloc generates
  140. both a "realloc" and a "realloc-to".
  141.  
  142. The variable _malstate provides interlocking so that when realloc
  143. calls malloc or free, which it sometimes does, an additional tracing
  144. line will not be generated, and so that no tracing will be generated
  145. before initialization is complete or if the trace file cannot be opened.
  146.  
  147. The associated shell script "prleak", containing three awk programs, 
  148. reads the $MALLOCTRACE or "malloc.out" (or other specified) file, and
  149. does an "nm" on the program supposed to have generated it ("a.out"
  150. by default).  It scans these outputs and produces a report of the
  151. high water level of allocated data (excluding that from stdio, as far
  152. as possible), the total amount of data remaining allocated at termin-
  153. ation, and the tracebacks of all calls that left data allocated at
  154. termination or that resulted in any error (including nonfatal ones
  155. such as frees of unallocated data).  The tracebacks give entries in
  156. forms such as "called from  5a9b [ _getframe + 42]", where 5a9b is in
  157. hexadecimal and 42 in decimal.
  158.  
  159.                         Mark Brader
  160.                         SoftQuad Inc.
  161.                         January 1987
  162. @@@End of TRACE_README
  163. echo x - NEW_VERSION_README 1>&2
  164. cat >NEW_VERSION_README <<'@@@End of NEW_VERSION_README'
  165. >From utai!uunet!ncifcrf.gov!elsie!ado Mon Aug  1 02:37:08 1988
  166. Received: by sq.sq.com id 21060; Mon, 1 Aug 88 02:36:59 EDT
  167. From:    ncifcrf.gov!elsie!ado
  168. Received: from fcs280s.ncifcrf.gov by a.cs.uiuc.edu with SMTP (UIUC-5.52/9.7)
  169.     id AA09603; Sun, 31 Jul 88 13:13:31 CDT
  170. Received: by fcs280s.ncifcrf.gov (4.0/NCIFCRF-1.0)
  171.     id AA05293; Sun, 31 Jul 88 14:15:06 EDT
  172. Received: by elsie.UUCP (5.51/4.7)
  173.     id AA15980; Sun, 31 Jul 88 14:11:42 EDT
  174. Date:    Sun, 31 Jul 88 12:51:42 EDT
  175. From:    ncifcrf.gov!elsie!ado (Arthur David Olson)
  176. Message-Id: <8807311811.AA15980@elsie.UUCP>
  177. To:    msb@sq.com
  178. Subject: Re:  Bug in Bill Sebok's malloc() package
  179. Status: RO
  180.  
  181. I get the right output from your sample code with the version of malloc we're
  182. using here at elsie; our version (Bill's with bug fixes) is attached.
  183.  
  184.                 --ado
  185.  
  186. @@@End of NEW_VERSION_README
  187. echo x - README.mtest2 1>&2
  188. cat >README.mtest2 <<'@@@End of README.mtest2'
  189. Article 1077 of net.sources:
  190. Path: sq!utfyzx!utgpu!water!watnot!watmath!clyde!rutgers!husc6!necntc!encore!vaxine!nw
  191. From: nw@vaxine.UUCP (Neil Webber)
  192. Newsgroups: net.sources
  193. Subject: malloc/free test program
  194. Message-ID: <417@vaxine.UUCP>
  195. Date: 16 Feb 87 20:49:49 GMT
  196. Organization: Automatix, Inc., Billerica, MA
  197. Lines: 460
  198.  
  199. A while back I asked the net if anyone had a malloc/free test program that
  200. would allocate and free randomly sized pieces of memory with random lifetimes
  201. (and fill them with patterns that would be checked for corruption).  I got
  202. a number of useful suggestions (best one: use the "diff" program as a
  203. malloc test ... it's brutal).  Eventually, I wound up writing my own
  204. test program, which actually helped me find a bug.
  205.  
  206. On the assumption that it might be useful to someone else, here it is.
  207. Please note:
  208.  
  209.         - No documentation (read the code to find out what it does).
  210.         - Could be extended in zillions of ways to make it more useful.
  211.         - No makefile, just compile "cc mtest.c"
  212.  
  213. A "shar" archive follows.
  214.  
  215. Neil Webber     Automatix Inc. (or current resident)    Billerica MA
  216.         {decvax,ihnp4,allegra}!encore!vaxine!nw
  217.  
  218. @@@End of README.mtest2
  219. echo x - README.mtest3 1>&2
  220. cat >README.mtest3 <<'@@@End of README.mtest3'
  221. Article 1086 of net.sources:
  222. Path: sq!utfyzx!utgpu!water!watnot!watmath!clyde!rutgers!lll-lcc!ptsfa!amdahl!rtech!daveb
  223. From: daveb@rtech.UUCP (Dave Brower)
  224. Newsgroups: net.sources
  225. Subject: Another allocator tester
  226. Message-ID: <665@rtech.UUCP>
  227. Date: 17 Feb 87 19:00:13 GMT
  228. References: <417@vaxine.UUCP>
  229. Organization: Relational Technology, Alameda CA
  230. Lines: 204
  231.  
  232. > A while back I asked the net if anyone had a malloc/free test program that 
  233. > would allocate and free randomly sized pieces of memory with random
  234. > lifetimes... [ and one follows ]
  235.  
  236. Here is a program I've been using recently.  It is a lot more intensive
  237. than Neil Webber's, and shows you what the process size is doing.  I am
  238. usually comfortable when I can run an allocator through 10 million or so
  239. loops with out a problem.
  240.  
  241. A useful addition would be computation of kilo-core-seconds.
  242.  
  243. As usual, no documentation and best wishes.
  244.  
  245. -dB
  246.  
  247. ---------------- cut here ----------------
  248. @@@End of README.mtest3
  249. echo x - mallck.1 1>&2
  250. cat >mallck.1 <<'@@@End of mallck.1'
  251. .TH MALLCK 1 "25 August 1988"
  252. .ds li /usr/lib/malloctrace.a
  253. .SH NAME
  254. mallck \- check memory allocation and deallocation calls
  255. .SH SYNOPSIS
  256. .B mallck
  257. [ program ] [ tracefile ]
  258. .SH DESCRIPTION
  259. .IX  mallck  ""  "\fLmallck\fP \(em check memory allocation and deallocation calls
  260. .I Mallck
  261. is used in conjunction with the library
  262. .IR \*(li .
  263. .PP
  264. If a program is linked with that library (as the last library searched),
  265. then when it is run, it will create a trace file of all the calls to
  266. .IR malloc ,
  267. .IR realloc ", and
  268. .IR free .
  269. The name of the trace file is taken from the environment variable
  270. \s-2MALLOCTRACE\s+2, or if that is undefined, defaults to
  271. .IR malloc.out .
  272. Output to the file is flushed after each entry unless the environment variable
  273. \s-2MALLOCTRACEBUF\s+2 is nonnull.
  274. .PP
  275. .I Mallck
  276. is used to scan this file and look for calls that do not pair up\(emeither
  277. .IR malloc s
  278. without
  279. .IR free s,
  280. or vice versa, or calls where the amount freed (taken from the
  281. internal information that
  282. .I free
  283. uses) does not correspond to the amount allocated.
  284. .I Mallck
  285. also reports the high-water mark of
  286. memory that it knows (see Bugs section) to have been allocated.
  287. .PP
  288. .I Mallck
  289. also examines the symbol table of the program, to format the tracebacks
  290. usefully.
  291. Its first argument
  292. .I program
  293. should be either the executable program, not stripped, or the output
  294. from running
  295. .I nm
  296. on the executable program.
  297. (Only the `T' entries are examined and their sequence does not matter, so
  298. .IR "nm -gp" "'s
  299. output would suffice.)
  300. If no arguments are given,
  301. .I a.out
  302. is used for
  303. .IR program .
  304. .PP
  305. The second argument
  306. .I malloctrace
  307. is the trace file described above.
  308. If omitted, the same defaults apply as above.
  309. .SH AUTHOR
  310. Mark Brader, SoftQuad Inc., 1987-88.
  311. .PP
  312. Based on the paper
  313. .I "A Technique for Finding Storage Allocation Errors in C-language Programs
  314. by David R. Barach, David H. Taenzer, and Robert E. Wells, in
  315. .IR "SIGPLAN Notices" ,
  316. .BR 17 ,
  317. 5 (May 1982).
  318. .PP
  319. The
  320. .I malloc
  321. family functions to which the tracing was added to create
  322. .I \*(li
  323. were the public-domain ones by Bill Sebok, then of Princeton University,
  324. with modifications by Arthur David Olson of the National Institutes of Health.
  325. .SH DIAGNOSTICS
  326. Self-explanatory, as they say.
  327. Since memory being allocated but never freed may be a harmless
  328. situation, it is reported in lower case, while other messages
  329. are more emphatic.
  330. .SH SEE ALSO
  331. nm(1), malloc(3)
  332. .SH FILES
  333. a.out
  334. .br
  335. malloc.out
  336. .br
  337. \*(li
  338. .SH BUGS
  339. There is no way to verify that the trace
  340. file did in fact come from the program
  341. .IR program ;
  342. nonsensical tracebacks are the only hint.
  343. Even if the program is the correct one, functions declared static are
  344. not seen by
  345. .I nm
  346. and thus tracebacks from calls in such functions will be misleading.
  347. .PP
  348. Due to interactions between
  349. .I stdio
  350. and the traced
  351. .I malloc
  352. family, programs may be unstable as to whether they report the
  353. calls to the
  354. .I malloc
  355. family that
  356. .I stdio
  357. functions may make.
  358. Thus
  359. .I stdio
  360. buffers may be counted in the high-water mark or not, depending only
  361. on what input the program received.
  362. The first
  363. .I stdio
  364. buffer is never reported.
  365. .PP
  366. Calls to
  367. .I realloc
  368. are treated internally as successive calls to two functions,
  369. .I realloc
  370. and 
  371. .I realloc-to
  372. (equivalent to
  373. .I free
  374. and
  375. .IR malloc ),
  376. and are so referred to in the output report.
  377. .PP
  378. The sizes reported in ``never freed'' messages
  379. exclude the overhead added by the
  380. .I malloc
  381. family functions, even though the allocation statistics do report it.
  382. (This is because the overhead may differ slightly on otherwise identical calls,
  383. and if this is ignored, their reports can be combined.)
  384. .PP
  385. The code in
  386. .I \*(li
  387. that produces the calling stack traceback was written
  388. without the aid of documentation on the Sun's stack format.
  389. Since it depends on the stack format, it is not portable.
  390. .PP
  391. The format of the trace file is somewhat verbose and it can rapidly
  392. consume large amounts of disk space.
  393. A pipe cannot be used because
  394. .I mallck
  395. reads the trace file twice.
  396. .SH NOTES
  397. .I Mallck
  398. is a shell script consisting principally of 3 invocations of
  399. .IR awk ,
  400. 3 of
  401. .IR sort ,
  402. and one each of
  403. .IR sed ,
  404. .IR grep ", and
  405. .IR nm .
  406. @@@End of mallck.1
  407. echo x - malloc.3 1>&2
  408. cat >malloc.3 <<'@@@End of malloc.3'
  409. .TH MALLOC 3  "30 June 1986"
  410. .SH NAME
  411. malloc, free, realloc \- memory allocator
  412. .SH SYNOPSIS
  413. .nf
  414. .B char *malloc(size)
  415. .B Size size;
  416. .PP
  417. .B void free(ptr)
  418. .B char *ptr;
  419. .PP
  420. .B char *realloc(ptr, size)
  421. .B char *ptr;
  422. .B Size size;
  423. .PP
  424. .B extern char endfree
  425. .PP
  426. .B extern void (*mlabort)()
  427. .fi
  428. .PP
  429. Where
  430. .I Size
  431. is an integer large enough to hold a char pointer.
  432. .SH DESCRIPTION
  433. .I Malloc
  434. and
  435. .I free
  436. provide a simple general-purpose memory allocation package.
  437. .I Malloc
  438. returns a pointer to a block of at least
  439. .I size
  440. bytes beginning on the boundary of the most stringent alignment required
  441. by the architecture.
  442. .PP
  443. The argument to
  444. .I free
  445. is a pointer to a block previously allocated by
  446. .IR malloc ;
  447. this space is made available for further allocation,
  448. but its contents are left undisturbed.
  449. .PP
  450. Needless to say, grave disorder will result if the space assigned by
  451. .I malloc
  452. is overrun or if some random number is handed to
  453. .IR free .
  454. .PP
  455. .I Malloc
  456. maintains multiple lists of free blocks according to size,
  457. allocating space from the appropriate list.
  458. It calls
  459. .I brk
  460. (see
  461. .IR brk (2))
  462. to get more memory from the system when there is no
  463. suitable space already free.
  464. .PP
  465. .I Free
  466. makes an attempt to merge newly freed memory with adjacent free areas.
  467. If the result of this merging is an area that touches the system break
  468. (the current location of the highest valid address of the data segment of the
  469. process) and if
  470. .I
  471. endfree
  472. has a non-zero value,  then break is moved back, contracting the process
  473. size and releasing the memory back to the system.
  474. .PP
  475. By default
  476. .I endfree
  477. has a value of 0, which disables the release of memory back to the system.
  478. .PP
  479. It is valid to also allocate memory by the use of
  480. .I sbrk(3)
  481. or by moving up the break with
  482. .I brk(3).
  483. This memory may be reclaimed and returned to
  484. the \fImalloc\fP/\fIfree\fP arena by the use of
  485. .I forget
  486. (see \fIforget\fP(3)).
  487. .PP
  488. .I Realloc
  489. changes the size of the block pointed to by
  490. .I ptr
  491. to
  492. .I size
  493. bytes and returns a pointer to the (possibly moved) block.
  494. The contents will be unchanged up to the lesser of the new and old sizes.
  495. .PP
  496. In order to be compatible with older versions,
  497. if
  498. .I endfree
  499. is 0, then
  500. .I realloc
  501. also works if
  502. .I ptr
  503. points to a block freed since the last call of
  504. .I malloc
  505. or
  506. .I realloc.
  507. Sequences of
  508. .I free, malloc
  509. and
  510. .I realloc
  511. were previously used to attempt storage compaction.
  512. This procedure is no longer recommended.
  513. In this implementation
  514. .I Realloc,
  515. .I malloc
  516. and
  517. .I free
  518. do a fair amount of their own storage compaction anyway.
  519. .SH DIAGNOSTICS
  520. .I Malloc, realloc
  521. return a null pointer (0) if there is no available memory or if the arena
  522. has been detectably corrupted by storing outside the bounds of a block.
  523. .I Realloc
  524. makes an attempt to detect and return a null pointer when the break has been
  525. moved so that the requested address is no longer valid.
  526. .I Malloc
  527. may be recompiled to check the arena very stringently on every transaction;
  528. those sites with a source code license may do this by recompiling the source
  529. with  -Ddebug .
  530. .PP
  531. On detection of corruption of the malloc arena the normal response is an
  532. abort with a core dump.  This response can be changed by placing a pointer to
  533. a function with the desired response into the extern pointer
  534. .I mlabort.
  535. .SH ALGORITHM
  536. .I Malloc
  537. returns a block of size equal to the size requested plus an overhead (24
  538. bytes for a 32 bit machine).
  539. Freed memory is linked into a chain selected by the size of the freed area
  540. (currently, memory size of items in a chain is between two adjacent powers of
  541. 2).
  542. The search for memory starts with the chain whose length index is at least
  543. equal to the size of the request and proceeds if unsuccessful to larger
  544. memory size chains.  If there is any surplus memory left after the filling
  545. of a request it is returned to the appropriate free list chain.
  546. .SH BUGS
  547. When
  548. .I realloc
  549. returns 0, the block pointed to by
  550. .I ptr
  551. may have been destroyed.
  552. @@@End of malloc.3
  553. echo x - forget.3 1>&2
  554. cat >forget.3 <<'@@@End of forget.3'
  555. .TH FORGET 3  "30 June 1986"
  556. .SH NAME
  557. forget \- reclaim sbrk'ed memory into malloc arena
  558. .SH SYNOPSIS
  559. .nf
  560. .B void forget(ptr)
  561. .B char *ptr;
  562. .PP
  563. .B extern char endfree
  564. .SH DESCRIPTION
  565. .I Forget
  566. provides a way of reclaiming memory obtained by
  567. .I sbrk(3)
  568. and returning it to the malloc arena.  All such memory above
  569. .I ptr
  570. (the "forget point") is marked free and merged if possible with adjacent
  571. free areas.  If
  572. .I endfree
  573. is non-zero any such memory adjacent to the "break" (the highest valid
  574. data address for the process) is released to the system by moving back
  575. the break.
  576. .PP
  577. This function was written to provide the functionality of the Forth
  578. FORGET primitive in an environment where
  579. a dictionary is grown by
  580. .I sbrk
  581. and
  582. .I malloc
  583. and
  584. .I free
  585. are also present.
  586. .SH BUGS
  587. When the specified forget point is below the initial end of the program,
  588. disaster can result.
  589. @@@End of forget.3
  590. echo x - mallck 1>&2
  591. cat >mallck <<'@@@End of mallck'
  592. #
  593. # mallck
  594. # Mark Brader, SoftQuad Inc., 1987
  595. #
  596. # NOT copyright by SoftQuad.  - msb, 1988
  597. #
  598. # sccsid @(#)mallck    1.4 88/08/24
  599. #
  600. # Checks a malloc trace file as produced by modified forms of malloc,
  601. # free, and realloc -- locally in /usr/lib/malloctrace.a -- for any
  602. # incorrectly paired allocations and frees, and any other problems.
  603. # Also computes a few statistics from the data.
  604. #
  605. # Usage:
  606. #    mallck [a.out] [${MALLOCTRACE-malloc.out}]
  607. # or
  608. #    mallck nm.out  [${MALLOCTRACE-malloc.out}]
  609. #
  610. # Both arguments optional, defaults as indicated.  nm.out is the result of
  611. # running nm on the program; only the T lines are significant.
  612. #
  613.  
  614. # The contents of the malloc trace file look like this:
  615. #
  616. #    malloc of 71 gets 104 at 143692
  617. #    caller 000020e8
  618. #    caller 0000204c
  619. #    
  620. #    free of 44 at 143500
  621. #    caller 000020f8
  622. #    caller 0000204c
  623. #    
  624.  
  625. # First, three awk programs.  Unfortunately, while it's most convenient
  626. # to put them in sh variables, it runs sh near its limits, so we use sed
  627. # to pack the programs a bit first...
  628.  
  629.  
  630. # Look up locations in symbol table.  This program reads the "caller"
  631. # entries in the malloc trace file, and the output of nm, and produces
  632. # output of this form:
  633. #
  634. #    0000204c     204c start 44
  635. #    000020b8     20b8 _main 24
  636. #    000020c8     20c8 _main 40
  637. #    000020d8     20d8 _main 56
  638.  
  639. SYMTAB=`sed -e "s/    //" -e "s/ *#.*//" <<'Eot'
  640. BEGIN {
  641.     digit["a"] = 10        # Hex into decimal without scanf
  642.     digit["b"] = 11
  643.     digit["c"] = 12
  644.     digit["d"] = 13
  645.     digit["e"] = 14
  646.     digit["f"] = 15
  647.     for (i = 0; i <= 9; ++i) digit[i] = i
  648.     func = "0"
  649.     funaddr = 0
  650. }
  651. /./ {
  652.     addr = 0
  653.     for (i = 1; i <= 8; ++i) addr = 16*addr + digit[substr($1,i,1)]
  654.     if (addr + 1 == addr) {
  655.         printf " --- **** WARNING: conversion of hex %s to decimal" \
  656.             " %d may be inaccurate!\n", $1, addr
  657.             # Single precision floating point!
  658.     }
  659.     if ($2 == "T") {
  660.         func = $3
  661.         funaddr = addr
  662.     } else \
  663.         printf "%8.8x %8x %s %d\n", addr, addr, func, addr - funaddr
  664. }
  665. Eot
  666. `
  667.  
  668. # Examine calls to malloc et al, and locate any problems.
  669. # This program reads the malloc trace file again, and produces output of
  670. # the following form, which is then sorted and filtered through uniq -c.
  671. # The part before the "---" is a complete call stack traceback.
  672. # There are also summary lines.
  673. #
  674. #     00002110 0000204c --- malloc - size 21 - never freed
  675. #     00002124 0000204c --- realloc-to - size 21 - never freed
  676. #
  677. # The sizes shown are the requested sizes, not the actual ones including
  678. # overhead.  This is so that duplicate entries can be reduced accurately
  679. # by uniq -c.  However, when errors are reported, actual sizes are shown too.
  680. #
  681.  
  682. FIND=`sed -e "s/    //" -e "s/ *#.*//" <<'Eot'
  683. BEGIN {
  684.         # So null input is harmless ...
  685.     alact[""] = totalloc = maxalloc = maxloc = 0
  686.  
  687.         # for waking up recipients of important errors
  688.     bang = " *****************"
  689. }
  690.  
  691. /of/ {
  692.     act = $1
  693.     reqsize = $3
  694.     caller = ""
  695.     if ($4 == "gets") {
  696.         gotsize = $5
  697.         loc = $7
  698.     } else {
  699.         gotsize = reqsize
  700.         loc = $5
  701.     }
  702. }
  703.  
  704. /caller/ {
  705.     caller = caller " " $2        # concatenate traceback together
  706. }
  707.  
  708. /^$/ {
  709.     if (act == "malloc" || act == "realloc-to") {
  710.  
  711.         if (loc == 0) {
  712.             printf "%s --- %s - size %s - ALLOCATION FAILED%s\n", \
  713.                 caller, act, reqsize, bang
  714.  
  715.         } else {
  716.                 # just take note for later reference
  717.             alcall[loc] = caller
  718.             alreq [loc] = reqsize
  719.             algot [loc] = gotsize
  720.             alact [loc] = act
  721.             totreq += reqsize
  722.             totgot += gotsize
  723.             if (maxreq < totreq) maxreq = totreq
  724.             if (maxgot < totgot) maxgot = totgot
  725.             if (maxloc < gotsize + loc) maxloc = gotsize + loc
  726.         }
  727.  
  728.     } else {
  729.                 # Must be free or realloc - check the data
  730.  
  731.         if (alact[loc]) {
  732.             if (algot[loc] != gotsize) {
  733.                 printf "%s --- %s - size %s - actual %s -" \
  734.                     " WRONG SIZE LATER FREED%s\n", \
  735.                     alcall[loc], alact[loc], alreq[loc], \
  736.                     algot[loc], bang
  737.                 printf "%s --- %s - size %s -" \
  738.                     " ACTUAL ALLOCATED SIZE WAS %s%s\n", \
  739.                     caller, act, gotsize, algot[loc], bang
  740.             }
  741.             alact[loc] = ""
  742.             totgot -= gotsize
  743.             totreq -= alreq[loc]
  744.  
  745.         } else {
  746.             printf "%s --- %s - size %s - UNALLOCATED%s\n", \
  747.                 caller, act, gotsize, bang
  748.         }
  749.     }
  750. }
  751.  
  752. END {
  753.                 # check for never-freed space
  754.     for (loc in alact)
  755.         if (alact[loc])
  756.             printf "%s --- %s - size %s -" \
  757.                 " never freed\n", \
  758.                 alcall[loc], alact[loc], alreq[loc]
  759.  
  760.         # The following statistics will print at the top of the
  761.         # final output, by a little trickery -- their beginnings
  762.         # are chosen to sort before the other records (and to
  763.         # leave them in the desired order after sorting)
  764.  
  765.     print " --- ****** ALLOCATION STATISTICS (excluding most stdio)"
  766.     printf " --- ****** Greatest allocated address: %d (hex %x)\n", \
  767.             maxloc - 1, maxloc - 1
  768.     print " --- ****** High-water allocation level: " \
  769.             maxreq " bytes (+ " maxgot-maxreq " overhead)"
  770.     print " --- ****** Total of memory never freed: " \
  771.             totreq " bytes (+ " totgot-totreq " overhead)"
  772. }
  773. Eot
  774. `
  775.  
  776. # Format the output of the 2nd awk program using the output
  777. # of the 1st to display symbolic locations
  778.  
  779. REPORT=`sed -e "s/    //" -e "s/ *#.*//" <<'Eot'
  780.  
  781. ! / --- / {
  782.     func[$1] = $3
  783.     offs[$1] = $4
  784.     nozeros[$1] = $2
  785.     if (maxlen < length($3)) maxlen = length($3)
  786.     if (maxdig < length($4)) maxdig = length($4)
  787. }
  788.  
  789. / --- / {
  790.     for (punct = 1; $punct != "---"; ++punct) {;} # Where in line is "---"?
  791.  
  792.     if (punct > 2) printf "\n\n"
  793.     if ($1 > 1) printf "occurring %d times - ", $1    # Bless uniq -c!
  794.  
  795.     for (i = punct + 1; i <= NF; ++i) printf "%s ", $i
  796.     printf "\n"
  797.  
  798.     if (punct > 2) {
  799.         for (i = 2; i < punct; ++i) {
  800.             if (i == 2) printf "\n\tcalled"; else printf "\t"
  801.             printf "\tfrom %8s [%" maxlen "s + %" maxdig "d]\n", \
  802.                 nozeros[$i], func[$i], offs[$i]
  803.         }
  804.     }
  805. }
  806.  
  807. Eot
  808. `
  809.  
  810. # Default arguments:
  811.  
  812. BIN=${1-a.out}
  813. TRACE=${2-${MALLOCTRACE-malloc.out}}
  814.  
  815. # And do it...
  816.  
  817. (
  818.     (
  819.         (sed -n '/caller /s///p' $TRACE || exit) \
  820.             | sort -u
  821.         (nm -gp $BIN 2>/dev/null || cat $BIN) \
  822.             | grep ' T '
  823.     ) \
  824.         | sort | awk "$SYMTAB"
  825.     awk "$FIND" $TRACE | sort | uniq -c
  826. ) \
  827. | awk "$REPORT"
  828. @@@End of mallck
  829. echo chmod +x mallck
  830. chmod +x mallck
  831. echo x - calloc.c 1>&2
  832. cat >calloc.c <<'@@@End of calloc.c'
  833. #include "malloc.h"
  834. #define NULL 0
  835.  
  836.  
  837. /* NOT copyright by SoftQuad. - msb, 1988 */
  838. #ifndef lint
  839. static char *SQ_SccsId = "@(#)calloc.c    1.2 88/08/24";
  840. #endif
  841. /*
  842. ** And added by ado. . .
  843. */
  844.  
  845. char *
  846. calloc(n, s)
  847. unsigned    n;
  848. unsigned    s;
  849. {
  850.     unsigned    cnt;
  851.     char *        cp;
  852.  
  853.     cnt = n * s;
  854.     cp = malloc(cnt);
  855.     if (cp != NULL)
  856.         bzero(cp, (int) cnt);
  857.     return cp;
  858. }
  859.  
  860. void
  861. cfree(mem)
  862. char *    mem;
  863. {
  864.     free(mem);
  865. }
  866.  
  867. @@@End of calloc.c
  868. echo x - forget.c 1>&2
  869. cat >forget.c <<'@@@End of forget.c'
  870. #include "malloc.h"
  871. #define NULL 0
  872.  
  873. /* NOT copyright by SoftQuad. - msb, 1988 */
  874. #ifndef lint
  875. static char *SQ_SccsId = "@(#)forget.c    1.4 88/08/24";
  876. #endif
  877. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  878.  *  forget                William L. Sebok
  879.  * A "smarter" malloc v1.0        Sept. 24, 1984 rev. June 30,1986
  880.  *            Then modified by Arthur David Olsen
  881.  *
  882.  *    forget returns to the malloc arena all memory allocated by sbrk()
  883.  *     above "bpnt".
  884.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  885.  
  886. void
  887. forget(bpnt)
  888. char *bpnt;
  889. {
  890.     register struct overhead *p, *q, *r, *b;
  891.     register Size l;
  892.     struct overhead *crbrk;
  893.     char pinvalid, oendfree;
  894.  
  895.     /*
  896.      * b = forget point
  897.      * p = beginning of entry
  898.      * q = end of entry, beginning of gap
  899.      * r = end of gap, beginning of next entry (or the break)
  900.      * pinvalid = true when groveling at forget point
  901.      */
  902.  
  903.     pinvalid = 0;
  904.     oendfree = endfree;    endfree = 0;
  905.     b = (struct overhead *)bpnt;
  906.     p = FROMADJ(adjhead.q_back);
  907.     r = crbrk = (struct overhead *)CURBRK;
  908.  
  909.     for (;pinvalid == 0 && b < r; p = FROMADJ(TOADJ(r = p)->q_back)) {
  910.         if ( p == FROMADJ(&adjhead)
  911.          || (q = (struct overhead *)((char *)p + p->ov_length)) < b
  912.         ) {
  913.             pinvalid = 1;
  914.             q = b;
  915.         }
  916.  
  917.         if (q == r)
  918.             continue;
  919.  
  920.         ASSERT(q < r,
  921. "\nforget: addresses in adjacency chain are out of order!\n");
  922.  
  923.         /* end of gap is at break */
  924.         if (oendfree && r == crbrk) {
  925.             (void)BRK((char *)q);    /* free it yourself */
  926.             crbrk = r = q;
  927.             continue;
  928.         }
  929.  
  930.         if (pinvalid)
  931.             q = (struct overhead *) /* align q pointer */
  932.                 (((long)q + (NALIGN-1)) & (~(NALIGN-1)));
  933.  
  934.         l = (char *)r - (char *)q;
  935.         /*
  936.          * note: unless something is screwy: (l%NALIGN) == 0
  937.          * as r should be aligned by this point
  938.          */
  939.  
  940.         if (l >= (int) sizeof(struct overhead)) {
  941.             /* construct busy entry and free it */
  942.             q->ov_magic = MAGIC_BUSY;
  943.             q->ov_length = l;
  944.             insque(TOADJ(q),TOADJ(p));
  945.             free((char *)q + sizeof(struct overhead));
  946.         } else if (pinvalid == 0) {
  947.             /* append it to previous entry */
  948.             p->ov_length += l;
  949.             if (p->ov_magic == MAGIC_FREE) {
  950.                 remque(TOBUK(p));
  951.                 {
  952.                     register struct qelem *    bp;
  953.  
  954.                     bp = &buckets[mlindx(p->ov_length)];
  955.                     if (bp > hifreebp)
  956.                         hifreebp = bp;
  957.                     insque(TOBUK(p),bp);
  958.                 }
  959.             }
  960.         }
  961.     }
  962.     endfree = oendfree;
  963.     if (endfree)
  964.         mlfree_end();
  965.     return;
  966. }
  967. @@@End of forget.c
  968. echo x - free.c 1>&2
  969. cat >free.c <<'@@@End of free.c'
  970. #include "malloc.h"
  971. #define NULL 0
  972.  
  973. /* NOT copyright by SoftQuad. - msb, 1988 */
  974. #ifndef lint
  975. static char *SQ_SccsId = "@(#)free.c    1.6 88/08/24";
  976. #endif
  977. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  978.  *  free                    William L. Sebok
  979.  * A "smarter" malloc v1.0        Sept. 24, 1984 rev. June 30,1986
  980.  *            Then modified by Arthur David Olsen
  981.  *            MALLOCTRACE added by Mark Brader
  982.  *
  983.  *     free takes a previously malloc-allocated area at mem and frees it.
  984.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  985.  
  986. free(mem)
  987. register char *mem;
  988. {
  989.     register struct overhead *p, *q;
  990.     void mlfree_end();
  991.  
  992. #ifdef    MALLOCTRACE    /* See ./TRACE_README */
  993.     extern enum _malstate _malstate;
  994.  
  995.     if (_malstate == S_INITIAL) _mal_init_trace();
  996. #endif
  997.  
  998.     if (mem == NULL)
  999.         return;
  1000.  
  1001.     p = (struct overhead *)(mem - sizeof(struct overhead));
  1002.  
  1003. #ifdef    MALLOCTRACE
  1004.     if (_malstate == S_TRACING)
  1005.         _mal_write_trace ("free", p->ov_length, p->ov_length, mem);
  1006. #endif
  1007.  
  1008.     /* not advised but allowed */
  1009.     if (p->ov_magic == MAGIC_FREE)
  1010.         return;
  1011.  
  1012.     if (p->ov_magic != MAGIC_BUSY) {
  1013.         mllcerr("attempt to free memory not allocated with malloc!\n");
  1014. #ifdef    MALLOCTRACE
  1015.         return;        /* mllcerr() normally doesn't return */
  1016. #endif
  1017.     }
  1018.  
  1019.     /* try to merge with previous free area */
  1020.     q = FROMADJ((TOADJ(p))->q_back);
  1021.  
  1022.     if (q != FROMADJ(&adjhead)) {
  1023.         ASSERT(q < p,
  1024. "\nfree: While trying to merge a free area with a lower adjacent free area,\n\
  1025.  addresses were found out of order!\n");
  1026.         /* If lower segment can be merged */
  1027.         if (   q->ov_magic == MAGIC_FREE
  1028.            && (char *)q + q->ov_length == (char *)p
  1029.         ) {
  1030.             /* remove lower address area from bucket chain */
  1031.             remque(TOBUK(q));
  1032.  
  1033.             /* remove upper address area from adjacency chain */
  1034.             remque(TOADJ(p));
  1035.  
  1036.             q->ov_length += p->ov_length;
  1037.             p->ov_magic = NULL;    /* decommission */
  1038.             p = q;
  1039.         }
  1040.     }
  1041.  
  1042.     /* try to merge with next higher free area */
  1043.     q = FROMADJ((TOADJ(p))->q_forw);
  1044.  
  1045.     if (q != FROMADJ(&adjhead)) {
  1046.         /* upper segment can be merged */
  1047.         ASSERT(q > p,
  1048. "\nfree: While trying to merge a free area with a higher adjacent free area,\n\
  1049.  addresses were found out of order!\n");
  1050.         if (     q->ov_magic == MAGIC_FREE
  1051.            &&    (char *)p + p->ov_length == (char *)q
  1052.         ) {
  1053.             /* remove upper from bucket chain */
  1054.             remque(TOBUK(q));
  1055.  
  1056.             /* remove upper from adjacency chain */
  1057.             remque(TOADJ(q));
  1058.  
  1059.             p->ov_length += q->ov_length;
  1060.             q->ov_magic = NULL;    /* decommission */
  1061.         }
  1062.     }
  1063.  
  1064.     p->ov_magic = MAGIC_FREE;
  1065.  
  1066.     /* place in bucket chain */
  1067.     {
  1068.         register struct qelem *    bp;
  1069.  
  1070.         bp = &buckets[mlindx(p->ov_length)];
  1071.         if (bp > hifreebp)
  1072.             hifreebp = bp;
  1073.         insque(TOBUK(p),bp);
  1074.     }
  1075.  
  1076.     if (endfree)
  1077.         mlfree_end();
  1078.  
  1079.     return;
  1080. }
  1081.  
  1082. void
  1083. mlfree_end()
  1084. {
  1085.     register struct overhead *p;
  1086.  
  1087.     p = FROMADJ(adjhead.q_back);
  1088.     if (    /* area is free and at end of memory */
  1089.             p->ov_magic == MAGIC_FREE
  1090.         &&    (char*)p + p->ov_length == (char *)CURBRK
  1091.     ) {
  1092.         p->ov_magic = NULL;    /* decommission (just in case) */
  1093.  
  1094.         /* remove from end of adjacency chain */
  1095.         remque(TOADJ(p));
  1096.  
  1097.         /* remove from bucket chain */
  1098.         remque(TOBUK(p));
  1099.  
  1100.         /* release memory to system */
  1101.         (void)BRK((char *)p);
  1102.     }
  1103.     return;
  1104. }
  1105. @@@End of free.c
  1106. echo x - init_trace.c 1>&2
  1107. cat >init_trace.c <<'@@@End of init_trace.c'
  1108. #ifdef    MALLOCTRACE
  1109.  
  1110. #include <stdio.h>
  1111. #include "malloc.h"
  1112.  
  1113.  
  1114. /* NOT copyright by SoftQuad. - msb, 1988 */
  1115. #ifndef lint
  1116. static char *SQ_SccsId = "@(#)init_trace.c    1.3 88/08/24";
  1117. #endif
  1118. /*
  1119.  * Open the trace output file.  The _malstate serves to prevent
  1120.  * any infinite recursion if stdio itself calls malloc.
  1121.  */
  1122.  
  1123. void
  1124. _mal_init_trace()
  1125. {
  1126.     char *filename, *bufflag;
  1127.     char *getenv();
  1128.     extern enum _malstate _malstate;
  1129.     extern int _malbuff;
  1130.     extern FILE *_malfp;
  1131.  
  1132.     if (_malstate != S_INITIAL)    /* Can't happen, but what the heck */
  1133.         return;
  1134.  
  1135.     _malstate = S_IN_STDIO;
  1136.  
  1137.     filename = getenv (TRACEENVVAR);
  1138.     if (filename == NULL)
  1139.         filename = TRACEFILE;
  1140.  
  1141.     _malfp = fopen (filename, "w");
  1142.     if (_malfp == NULL) {
  1143.  
  1144.         perror (filename);
  1145.         fprintf(stderr, "(will run without malloc tracing)\n");
  1146.  
  1147.     } else {
  1148.         /*
  1149.          * Nonportable kludge that should trigger a malloc
  1150.          * in stdio while doing no harm, and also reduce the
  1151.          * likelihood of a future malloc in stdio.
  1152.          */
  1153.  
  1154.         putc (0, _malfp);
  1155.         fflush (_malfp);
  1156.         fseek (_malfp, 0L, 0);
  1157.  
  1158.         /* Were we requested not to flush after each entry? */
  1159.  
  1160.         bufflag = getenv (TRACEBUFVAR);
  1161.         _malbuff = (bufflag != NULL && *bufflag != '\0');
  1162.  
  1163.         /* Initialization successful */
  1164.  
  1165.         _malstate = S_TRACING;
  1166.     }
  1167. }
  1168. #endif
  1169. @@@End of init_trace.c
  1170. echo x - malloc.c 1>&2
  1171. cat >malloc.c <<'@@@End of malloc.c'
  1172. #include "malloc.h"
  1173. #define NULL 0
  1174.  
  1175. /* NOT copyright by SoftQuad. - msb, 1988 */
  1176. #ifndef lint
  1177. static char *SQ_SccsId = "@(#)malloc.c    1.8 88/08/24";
  1178. #endif
  1179. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1180.  * A  "smarter" malloc v1.0            William L. Sebok
  1181.  *                    Sept. 24, 1984 rev. June 30,1986
  1182.  *            Then modified by Arthur David Olsen
  1183.  *            MALLOCTRACE added by Mark Brader
  1184.  *
  1185.  *    malloc allocates and returns a pointer to a piece of memory nbytes
  1186.  *    in size.
  1187.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  1188.  
  1189. #ifdef    MALLOCTRACE    /* See ./TRACE_README */
  1190.  
  1191. #include <stdio.h>
  1192. FILE *_malfp;
  1193. int _malbuff;
  1194.  
  1195. enum _malstate _malstate = S_INITIAL;
  1196.  
  1197. #endif
  1198.  
  1199. /* sizes of buckets currently proportional to log 2() */
  1200. static Size mlsizes[] = {0, 64, 128, 256, 512, 1024, 2048,
  1201.     4096, 8192, 16384, 32768, 65536, 131072,
  1202.     262144, 524288, 1048576, 2097152, 4194304};
  1203.  
  1204. /* head of adjacency chain */
  1205. struct qelem adjhead = { &adjhead, &adjhead };
  1206.  
  1207. /* head of bucket chains */
  1208. struct qelem buckets[NBUCKETS] = {
  1209.     &buckets[0],  &buckets[0],    &buckets[1],  &buckets[1],
  1210.     &buckets[2],  &buckets[2],    &buckets[3],  &buckets[3],
  1211.     &buckets[4],  &buckets[4],    &buckets[5],  &buckets[5],
  1212.     &buckets[6],  &buckets[6],    &buckets[7],  &buckets[7],
  1213.     &buckets[8],  &buckets[8],    &buckets[9],  &buckets[9],
  1214.     &buckets[10], &buckets[10],    &buckets[11], &buckets[11],
  1215.     &buckets[12], &buckets[12],    &buckets[13], &buckets[13],
  1216.     &buckets[14], &buckets[14],    &buckets[15], &buckets[15],
  1217.     &buckets[16], &buckets[16],    &buckets[17], &buckets[17]
  1218. };
  1219.  
  1220. struct qelem *    hifreebp = &buckets[0];
  1221.  
  1222. char endfree = 0;
  1223. void (*mlabort)() = {0};
  1224. void    mlfree_end();
  1225.  
  1226. char *
  1227. malloc(nbytes)
  1228.     unsigned nbytes;    /* for 4.3 compat. */
  1229. {
  1230.     register struct overhead *p, *q;
  1231.     register struct qelem *bucket;
  1232.     register Size surplus;
  1233.     Size mlindx();
  1234.  
  1235. #ifdef    MALLOCTRACE
  1236.     unsigned old_nbytes;
  1237.  
  1238.     old_nbytes = nbytes;
  1239.     if (_malstate == S_INITIAL) _mal_init_trace();
  1240. #endif
  1241.  
  1242.     nbytes = ((nbytes + (NALIGN-1)) & ~(NALIGN-1))
  1243.         + sizeof(struct overhead);
  1244.  
  1245.     for (
  1246.         bucket = &buckets[mlindx((Size) nbytes)];
  1247.         bucket <= hifreebp;
  1248.         bucket++
  1249.     ) { 
  1250.         register struct qelem *b;
  1251.         for(b = bucket->q_forw; b != bucket; b = b->q_forw) {
  1252.             p = FROMBUK(b);
  1253.             ASSERT(p->ov_magic == MAGIC_FREE,
  1254. "\nmalloc: Entry not marked FREE found on Free List!\n");
  1255.             if (p->ov_length >= nbytes) {
  1256.                 remque(b);
  1257.                 surplus = p->ov_length - nbytes;
  1258.                 goto foundit;
  1259.             }
  1260.         }
  1261.     }
  1262.  
  1263.     /* obtain additional memory from system */
  1264.     {
  1265.         register Size i;
  1266.         p = (struct overhead *)CURBRK;
  1267.  
  1268.         i = ((Size)p)&(NALIGN-1);
  1269.         if (i != 0)
  1270.             p = (struct overhead *)((char *)p + NALIGN - i);
  1271.  
  1272.         if (BRK((char *)p + nbytes)) {
  1273. #ifdef    MALLOCTRACE
  1274.             if (_malstate == S_TRACING)
  1275.                 _mal_write_trace ("malloc", (Size) old_nbytes,
  1276.                             (Size) 0, (char*) 0);
  1277. #endif
  1278.             return(NULL);
  1279.         }
  1280.  
  1281.         p->ov_length = nbytes;
  1282.         surplus = 0;
  1283.  
  1284.         /* add to end of adjacency chain */
  1285.         ASSERT((FROMADJ(adjhead.q_back)) < p,
  1286. "\nmalloc: Entry in adjacency chain found with address lower than Chain head!\n"
  1287.             );
  1288.         insque(TOADJ(p),adjhead.q_back);
  1289.     }
  1290.  
  1291. foundit:
  1292.     /* mark surplus memory free */
  1293.     if (surplus > (int) sizeof(struct overhead)) {
  1294.         /* if big enough, split it up */
  1295.         q = (struct overhead *)((char *)p + nbytes);
  1296.  
  1297.         q->ov_length = surplus;
  1298.         p->ov_length = nbytes;
  1299.         q->ov_magic = MAGIC_FREE;
  1300.  
  1301.         /* add surplus into adjacency chain */
  1302.         insque(TOADJ(q),TOADJ(p));
  1303.  
  1304.         /* add surplus into bucket chain */
  1305.         {
  1306.             register struct qelem *    bp;
  1307.  
  1308.             bp = &buckets[mlindx(surplus)];
  1309.             if (bp > hifreebp)
  1310.                 hifreebp = bp;
  1311.             insque(TOBUK(q),bp);
  1312.         }
  1313.     }
  1314. #ifdef    MALLOCTRACE
  1315.     else
  1316.         nbytes += surplus;
  1317.  
  1318.     if (_malstate == S_TRACING)
  1319.         _mal_write_trace ("malloc", (Size) old_nbytes, (Size) nbytes,
  1320.                     (char *) p + sizeof (struct overhead));
  1321. #endif
  1322.  
  1323.     p->ov_magic = MAGIC_BUSY;
  1324.     return((char*)p + sizeof(struct overhead));
  1325. }
  1326.  
  1327. /*
  1328.  * select the proper size bucket
  1329.  */
  1330. Size
  1331. mlindx(n)
  1332. register Size n;
  1333. {
  1334.     register Size *p;
  1335.  
  1336.     p = mlsizes;
  1337.     p[NBUCKETS - 1] = n;
  1338.     /* Linear search. */
  1339.     while (n > *p++)
  1340.         ;
  1341.     return (p - 1) - mlsizes;
  1342. }
  1343.  
  1344. void
  1345. mllcerr(p)
  1346. char *p;
  1347. {
  1348.     register char *q;
  1349.     q = p;
  1350.     while (*q++);    /* find end of string */
  1351.     (void)write(2,p,q-p-1);
  1352. #ifndef    MALLOCTRACE
  1353.     if (mlabort)
  1354.         (*mlabort)();
  1355. #ifdef debug
  1356.     else
  1357.         abort();
  1358. #endif debug
  1359. #endif    MALLOCTRACE
  1360. }
  1361.  
  1362. #ifndef vax
  1363. /*
  1364.  * The vax has wondrous instructions for inserting and removing items into
  1365.  * doubly linked queues.  On the vax the assembler output of the C compiler is
  1366.  * massaged by an sed script to turn these function calls into invocations of
  1367.  * the insque and remque machine instructions.
  1368.  */
  1369.  
  1370. void
  1371. insque(item,queu)
  1372. register struct qelem *item, *queu;
  1373. /* insert "item" after "queu" */
  1374. {
  1375.     register struct qelem *pueu;
  1376.     pueu = queu->q_forw;
  1377.     item->q_forw = pueu;
  1378.     item->q_back = queu;
  1379.     queu->q_forw = item;
  1380.     pueu->q_back = item;
  1381. }
  1382.  
  1383. void
  1384. remque(item)
  1385. register struct qelem *item;
  1386. /* remove "item" */
  1387. {
  1388.     register struct qelem *queu, *pueu;
  1389.     pueu = item->q_forw;
  1390.     queu = item->q_back;
  1391.     queu->q_forw = pueu;
  1392.     pueu->q_back = queu;
  1393. }
  1394. #endif
  1395. @@@End of malloc.c
  1396. echo x - malloc.h 1>&2
  1397. cat >malloc.h <<'@@@End of malloc.h'
  1398. /* NOT copyright by SoftQuad. - msb, 1988 */
  1399.  
  1400. /* SQ SccsId "@(#)malloc.h    1.6 88/08/24" */
  1401.  
  1402. /*LINTLIBRARY*/
  1403.  
  1404. #ifndef lint
  1405. #ifndef NOID
  1406. #endif /* !NOID */
  1407. #endif /* !lint */
  1408.  
  1409. #ifdef vax
  1410.  
  1411. struct qelem *    _p;
  1412. struct qelem *    _q;
  1413.  
  1414. #define remque(p)    { _p = (p); asm("remque    *__p,r0"); }
  1415. #define insque(p, q)    { _p = (p); _q = (q) ; asm("insque    *__p,*__q"); }
  1416.  
  1417. #endif /* vax */
  1418.  
  1419. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1420.  * A  "smarter" malloc                William L. Sebok
  1421.  *            Then modified by Arthur David Olsen
  1422.  *            MALLOCTRACE added by Mark Brader
  1423.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1424.  *    Algorithm:
  1425.  *     Assign to each area an index "n". This is currently proportional to
  1426.  *    the log 2 of size of the area rounded down to the nearest integer.
  1427.  *    Then all free areas of storage whose length have the same index n are
  1428.  *    organized into a chain with other free areas of index n (the "bucket"
  1429.  *    chain). A request for allocation of storage first searches the list of
  1430.  *    free memory.  The search starts at the bucket chain of index equal to
  1431.  *    that of the storage request, continuing to higher index bucket chains
  1432.  *    if the first attempt fails.
  1433.  *    If the search fails then new memory is allocated.  Only the amount of
  1434.  *    new memory needed is allocated.  Any old free memory left after an
  1435.  *    allocation is returned to the free list.
  1436.  *
  1437.  *      All memory areas (free or busy) handled by malloc are also chained
  1438.  *    sequentially by increasing address (the adjacency chain).  When memory
  1439.  *    is freed it is merged with adjacent free areas, if any.  If a free area
  1440.  *    of memory ends at the end of memory (i.e. at the break), and if the
  1441.  *    variable "endfree" is non-zero, then the break is contracted, freeing
  1442.  *    the memory back to the system.
  1443.  *
  1444.  *    Notes:
  1445.  *        ov_length field includes sizeof(struct overhead)
  1446.  *        adjacency chain includes all memory, allocated plus free.
  1447.  */
  1448.  
  1449. /* the following items may need to be configured for a particular machine */
  1450.  
  1451. /* alignment requirement for machine (in bytes) */
  1452. #define NALIGN    4
  1453.  
  1454. /* size of an integer large enough to hold a character pointer */
  1455. typedef    long    Size;
  1456.  
  1457. /*
  1458.  * CURBRK returns the value of the current system break, i.e., the system's
  1459.  * idea of the highest legal address in the data area.  It is defined as
  1460.  * a macro for the benefit of systems that have provided an easier way to
  1461.  * obtain this number (such as in an external variable)
  1462.  */
  1463.  
  1464. #ifndef CURBRK
  1465. #define CURBRK    sbrk(0)
  1466. extern char *sbrk();
  1467. #else /* CURBRK */
  1468. #    if    CURBRK == curbrk
  1469. extern Size curbrk;
  1470. #    endif
  1471. #endif /* CURBRK */
  1472.  
  1473. /*
  1474.  * note that it is assumed that CURBRK remembers the last requested break to
  1475.  * the nearest byte (or at least the nearest word) rather than the nearest page
  1476.  * boundary.  If this is not true then the following BRK macro should be
  1477.  * replaced with one that remembers the break to within word-size accuracy.
  1478.  */
  1479.  
  1480. #ifndef BRK
  1481. #define BRK(x)    brk(x)
  1482. extern char *brk();
  1483. #endif /* !BRK */
  1484.  
  1485. /* END of machine dependent portion */
  1486.  
  1487. #ifdef    MALLOCTRACE
  1488. /* Tracing of all calls to malloc, free, realloc... see ./TRACE_README */
  1489.  
  1490. enum _malstate {S_INITIAL, S_IN_STDIO, S_IN_REALLOC, S_TRACING};
  1491.  
  1492. #define    TRACEFILE    "malloc.out"    /* default output filename */
  1493.  
  1494. #undef    MALLOCTRACE        /* so the next line means what it says! */
  1495. #define    TRACEENVVAR    "MALLOCTRACE"    /* where to read nondefault name */
  1496. #define    MALLOCTRACE        /* cancel #undef! */
  1497.  
  1498. #define    TRACEBUFVAR    "MALLOCTRACEBUF"    /* No-flush request */
  1499. #endif
  1500.  
  1501. #define    MAGIC_FREE    0x548a934c
  1502. #define    MAGIC_BUSY    0xc139569a
  1503.  
  1504. #define NBUCKETS    18
  1505.  
  1506. struct qelem {
  1507.     struct qelem *q_forw;
  1508.     struct qelem *q_back;
  1509. };
  1510.  
  1511. struct overhead {
  1512.     struct qelem    ov_adj;        /* adjacency chain pointers */ 
  1513.     struct qelem    ov_buk;        /* bucket chain pointers */
  1514.     long        ov_magic;
  1515.     Size        ov_length;
  1516. };
  1517.  
  1518. /*
  1519.  * The following macros depend on the order of the elements in struct overhead
  1520.  */
  1521. #define TOADJ(p)    ((struct qelem *)(p))
  1522. #define FROMADJ(p)    ((struct overhead *)(p))
  1523. #define FROMBUK(p)    ((struct overhead *)( (char *)p - sizeof(struct qelem)))
  1524. #define TOBUK(p)    ((struct qelem *)( (char *)p + sizeof(struct qelem)))
  1525.  
  1526. /*
  1527.  * return to the system memory freed adjacent to the break 
  1528.  * default is Off
  1529.  */
  1530. extern char endfree;
  1531.  
  1532. /* head of adjacency chain */
  1533. extern struct qelem adjhead;
  1534.  
  1535. /* head of bucket chains */
  1536. extern struct qelem buckets[NBUCKETS];
  1537. extern struct qelem *    hifreebp;
  1538.  
  1539. extern void (*mlabort)();
  1540.  
  1541. #ifndef vax
  1542. extern void insque(), remque();
  1543. #endif
  1544. extern void mllcerr();
  1545. extern char *malloc(), *realloc();
  1546.  
  1547. #ifdef debug
  1548. # define ASSERT(p,q)    if (!(p)) mllcerr(q)
  1549. #else
  1550. # define ASSERT(p,q)    ((p),(q))
  1551. #endif
  1552. @@@End of malloc.h
  1553. echo x - mtest1.c 1>&2
  1554. cat >mtest1.c <<'@@@End of mtest1.c'
  1555.  
  1556. /* NOT copyright by SoftQuad. - msb, 1988 */
  1557. #ifndef lint
  1558. static char *SQ_SccsId = "@(#)mtest1.c    1.2 88/08/24";
  1559. #endif
  1560. /*
  1561.  * tstmalloc    this routine tests and exercizes the malloc/free package
  1562.  */
  1563. #include <stdio.h>
  1564. #include <setjmp.h>
  1565. #include "malloc.h"
  1566.  
  1567. jmp_buf env;
  1568.  
  1569. main(argc,argv)
  1570. int argc; char *argv[];
  1571. {
  1572.     char lin[100], arg1[20], arg2[20], arg3[20];
  1573.     char *res, *malloc(), *realloc();
  1574.     register struct overhead *p, *q;
  1575.     register struct qelem *qp;
  1576.     int arg, nargs, argn;
  1577.     int l;
  1578.     void malerror();
  1579.  
  1580.     mlabort = &malerror;
  1581.     setjmp(env);
  1582.  
  1583.     for (;;) {
  1584.         printf("*  ");
  1585.         if (fgets(lin,sizeof lin, stdin)== NULL)
  1586.             exit(0);
  1587.         nargs = sscanf(lin,"%s%s%s",arg1,arg2,arg3);
  1588.         switch (arg1[0]) {
  1589.  
  1590.         case 'b':
  1591.             if (nargs == 2) {
  1592.                 arg = atoi(arg2);
  1593.                 if (arg<0 ||  arg>=NBUCKETS)
  1594.                     goto bad;
  1595.  
  1596.                 qp = &buckets[arg];
  1597.                 printf("Bucket %2d\t\t\t  buk=%08lx %08lx\n",
  1598.                     arg, qp->q_forw,qp->q_back);
  1599.                 qp = qp->q_forw;
  1600.                 for (; qp != &buckets[arg]; qp = qp->q_forw) {
  1601.                     p = FROMBUK(qp);
  1602.                     if (dump(p))
  1603.                         break;
  1604.                 }
  1605.             } else {
  1606.                 printf("Buckets:");
  1607.                 for (qp=buckets; qp<&buckets[NBUCKETS];qp++){
  1608.                     if (qp->q_forw != qp)
  1609.                         printf(" %d", qp-buckets);
  1610.                 }
  1611.                 printf("\n");
  1612.             }
  1613.             break;
  1614.         case 'e':
  1615.             endfree = 1;
  1616.             break;
  1617.         case 'E':
  1618.             endfree = 0;
  1619.             break;
  1620.         case 'f':
  1621.             if (nargs != 2) goto bad;
  1622.             sscanf(arg2,"%lx",&arg);
  1623.             printf("free(%x)\n",arg);
  1624.             free(arg);
  1625.             break;
  1626.         case 'F':
  1627.             if (nargs != 2) goto bad;
  1628.             sscanf(arg2,"%lx",&arg);
  1629.             printf("forget(%x)\n",arg);
  1630.             forget(arg);
  1631.             break;
  1632.         case 'h':
  1633.             printf("\
  1634. b    print bucket chains that aren't empty\n\
  1635. b [n]    trace through bucket chains\n\
  1636. e    turn on freeing of end of memory\n\
  1637. E    turn off freeing of end of memory\n\
  1638. f addr        free addr\n\
  1639. F addr        forget below addr\n\
  1640. h    print this help file\n\
  1641. m bytes        malloc bytes\n\
  1642. q    quit\n\
  1643. r addr bytes    realloc\n\
  1644. s    print break addr\n\
  1645. S    sbrk count\n\
  1646. t    trace through adjacency chain\n\
  1647. ");
  1648.             break;
  1649.         case 'm':
  1650.             if (nargs != 2) goto bad;
  1651.             arg = atoi(arg2);
  1652.             res = malloc(arg);
  1653.             printf("malloc(%d) = %lx\n",arg, res);
  1654.             break;
  1655.         case 'r':
  1656.             if (nargs != 3) goto bad;
  1657.             sscanf(arg2,"%lx",&arg);
  1658.             argn = atoi(arg3);
  1659.             res = realloc(arg,argn);
  1660.             printf("realloc(%lx,%d) = %lx\n",arg,argn,res);
  1661.             break;
  1662.         case 'q':
  1663.             exit(0);
  1664.             break;
  1665.         case 's':
  1666.             printf("brk = %08x\n",sbrk(0));
  1667.             break;
  1668.         case 'S':
  1669.             if (nargs != 2) goto bad;
  1670.             sscanf(arg2,"%ld",&arg);
  1671.             printf("sbrk(%d)\n",arg);
  1672.             sbrk(arg);
  1673.             break;
  1674.         case 't':
  1675.             printf("\t\t\t\t\t\thead    adj=%08lx %08lx\n",
  1676.                 adjhead.q_forw,adjhead.q_back);
  1677.             for (qp = adjhead.q_forw; qp!=&adjhead; qp=qp->q_forw) { 
  1678.                 p = FROMADJ(qp);
  1679.                 if (dump(p))
  1680.                     break;
  1681.                 q = FROMADJ(qp->q_forw);
  1682.                 if (q==FROMADJ(&adjhead))
  1683.                     q = (struct overhead *)sbrk(0);
  1684.                 l = (char *)q - (char *)p - p->ov_length;
  1685.                 if (l>0)
  1686.                     printf("%08x free space  len=%8d\n",
  1687.                         (char *)p + p->ov_length, l);
  1688.             }
  1689.             break;
  1690.         default:
  1691.     bad:        printf("Bad command\n");
  1692.         }
  1693.     }
  1694. }
  1695.  
  1696. dump(p)
  1697. register struct overhead *p;
  1698. {
  1699.     register char *s;
  1700.     int stat = 0;
  1701.  
  1702.     if (p->ov_magic == MAGIC_FREE)
  1703.         s = "MAGIC_FREE ";
  1704.     else if (p->ov_magic == MAGIC_BUSY) 
  1705.         s = "MAGIC_BUSY ";
  1706.     else {
  1707.         s = "BAD MAGIC  ";
  1708.         stat = 1;
  1709.     }
  1710.         
  1711.     printf( "%08x %s len=%8d buk=%08x %08x adj=%08x %08x\n",
  1712.         (&p[1]),s,p->ov_length,p->ov_buk.q_forw,p->ov_buk.q_back,
  1713.         p->ov_adj.q_forw,p->ov_adj.q_back
  1714.     );
  1715.     return(stat);
  1716. }
  1717.  
  1718. void
  1719. malerror()
  1720. {
  1721.     write(2,"malloc error\n",13);
  1722.     longjmp(env,1);
  1723. }
  1724. @@@End of mtest1.c
  1725. echo x - mtest2.c 1>&2
  1726. cat >mtest2.c <<'@@@End of mtest2.c'
  1727. /* NOT copyright by SoftQuad Inc. -- msb, 1988 */
  1728. #ifndef lint
  1729. static char *SQ_SccsId = "@(#)mtest2.c    1.2 88/08/25";
  1730. #endif
  1731. #include <stdio.h>
  1732.  
  1733. extern int      atoi ();
  1734. extern long     random ();
  1735. extern char    *sbrk ();
  1736.  
  1737. extern char    *malloc ();
  1738. extern char    *realloc ();
  1739. extern int      free ();
  1740.  
  1741. struct memevent {
  1742.         int                     m_time;         /* time to go */
  1743.         char                   *m_memory;       /* malloc'ed mem */
  1744.         unsigned                m_size;         /* size of mem */
  1745.         int                     m_id;           /* id, for trace/debug */
  1746.         int                     m_realloc;      /* counter, for debugging */
  1747.         char                    m_pattern;      /* pattern in memory */
  1748.         struct memevent        *m_next;         /* linked list pointer */
  1749. };
  1750.  
  1751. #ifndef MAX_EVENTS
  1752. #define MAX_EVENTS      10000
  1753. #endif
  1754.  
  1755. struct memevent eventpool[ MAX_EVENTS ];
  1756.  
  1757. struct memevent *events;
  1758. struct memevent *free_events;
  1759.  
  1760. char stdout_buf[ BUFSIZ ];
  1761. char stderr_buf[ BUFSIZ ];
  1762.  
  1763. int time_to_go;
  1764. int new_probability;
  1765. int realloc_probability = 25;           /* XXX: should set from argv */
  1766. int stat_frequency;
  1767.  
  1768. main (argc, argv)
  1769. int argc;
  1770. char *argv[];
  1771. {
  1772.         init (argc, argv);
  1773.         run_test ();
  1774. }
  1775.  
  1776. /*
  1777.  * run_test ()
  1778.  *
  1779.  * Run the actual memory test.
  1780.  */
  1781.  
  1782. run_test ()
  1783. {
  1784.         while (time_to_go > 0) {
  1785.                 arrival ();
  1786.                 service ();
  1787.                 -- time_to_go;
  1788.                 if ((time_to_go % stat_frequency) == 0)
  1789.                         do_stats ();
  1790.         }
  1791. }
  1792.  
  1793. /*
  1794.  * arrival ()
  1795.  *
  1796.  * With probability new_probability/100, allocate a new piece
  1797.  * of memory with some randomly determined size and lifetime,
  1798.  * and add it to the memory event list.
  1799.  */
  1800.  
  1801. arrival ()
  1802. {
  1803.         if (free_events && odds (new_probability, 100)) {
  1804.                 register struct memevent *m;
  1805.                 register char *p;
  1806.  
  1807.                 m = free_events;
  1808.                 free_events = m->m_next;
  1809.                 m->m_next = NULL;
  1810.  
  1811.                                         /* XXX: let these be set from argv */
  1812.                 m->m_size = (unsigned) random_range (1, 100);
  1813.                 if (time_to_go < 100)
  1814.                         m->m_time = random_range (1, time_to_go);
  1815.                 else
  1816.                         m->m_time = random_range (1, 100);
  1817.  
  1818.                 m->m_pattern = (char) random_range (0, 127);
  1819.                 m->m_realloc = 0;
  1820.                 m->m_memory = malloc (m->m_size);
  1821.                 if (! m->m_memory)
  1822.                         out_of_memory ();
  1823.  
  1824.  
  1825.                 for (p = m->m_memory; p < & m->m_memory[ m->m_size ]; p++)
  1826.                         *p = m->m_pattern;
  1827.  
  1828.                 add_to_events (m);
  1829.         }
  1830. } /* arrival */
  1831.  
  1832. /*
  1833.  * do_stats ()
  1834.  */
  1835.  
  1836. do_stats ()
  1837. {
  1838.         register struct memevent *m;
  1839.         int i;
  1840.         long total;
  1841.  
  1842.         printf ("---------------------\nTIME Remaining: %d\n", time_to_go);
  1843.  
  1844.         /* print other interesting but implementation-dependent stuff here
  1845.            (like count of blocks in heap, size of heap, etc) */
  1846.  
  1847.         total = 0;
  1848.         for (i = 1, m = events; m != NULL; m = m->m_next, i++) {
  1849.                 printf ("EVENT %5d (id %5d): ", i, m->m_id);
  1850.                 printf ("SIZE %4d, ", m->m_size);
  1851.                 printf ("PATTERN 0x%02x, ", m->m_pattern & 0xFF);
  1852.                 printf ("TIME %4d ", m->m_time);
  1853.                 if (m->m_realloc > 0)
  1854.                         printf ("REALLOC %d", m->m_realloc);
  1855.                 printf ("\n");
  1856.                 total += m->m_size;
  1857.         }
  1858.         printf ("TOTAL events %d, allocated memory %d\n", i-1, total);
  1859.         (void) fflush (stdout);
  1860. } /* do_stats */
  1861.  
  1862. /*
  1863.  * service ()
  1864.  *
  1865.  * Decrement the time remaining on the head event.  If
  1866.  * it's time is up (zero), service it.
  1867.  *
  1868.  * Servicing an event generally means free'ing it (after checking
  1869.  * for corruption).  It is also possible (realloc_probability) to
  1870.  * realloc the event instead.
  1871.  */
  1872.  
  1873. service ()
  1874. {
  1875.         register struct memevent *m;
  1876.  
  1877.         if ((m = events) != NULL)
  1878.                 -- m->m_time;
  1879.  
  1880.         while (m != NULL && m->m_time == 0) {
  1881.                 register char *p;
  1882.  
  1883.                 for (p = m->m_memory; p < & m->m_memory[ m->m_size ]; p++) {
  1884.                         if (*p != m->m_pattern)
  1885.                                 corrupted ();
  1886.                 }
  1887.  
  1888.                 events = m->m_next;     /* delete this event */
  1889.  
  1890.                 if (time_to_go > 1 && odds (realloc_probability, 100))
  1891.                         realloc_event (m);
  1892.                 else
  1893.                         free_event (m);
  1894.  
  1895.                 m = events;
  1896.  
  1897.         }
  1898. } /* service */
  1899.  
  1900. /*
  1901.  * free_event (m)
  1902.  *
  1903.  * Called to free up the given event, including its memory.
  1904.  */
  1905.  
  1906. free_event (m)
  1907. register struct memevent *m;
  1908. {
  1909.         free (m->m_memory);
  1910.         m->m_next = free_events;
  1911.         free_events = m;
  1912. }
  1913.  
  1914. /*
  1915.  * realloc_event (m)
  1916.  *
  1917.  * Called from service(), to reallocate an event's memory,
  1918.  * rather than freeing it.
  1919.  */
  1920.  
  1921. realloc_event (m)
  1922. register struct memevent *m;
  1923. {
  1924.         register char *p;
  1925.         unsigned new_size;
  1926.         unsigned min_size;
  1927.  
  1928.                                         /* XXX: let these be set from argv */
  1929.         new_size = (unsigned) random_range (1, 100);
  1930.  
  1931.         ++ m->m_realloc;                /* for stats */
  1932.         m->m_memory = realloc (m->m_memory, new_size);
  1933.         if (! m->m_memory)
  1934.                 out_of_memory ();
  1935.  
  1936.         m->m_next = NULL;
  1937.  
  1938.         if (time_to_go < 100)
  1939.                 m->m_time = random_range (1, time_to_go - 1);
  1940.         else
  1941.                 m->m_time = random_range (1, 100);   /* XXX: should set from argv */
  1942.  
  1943.         min_size = new_size > m->m_size ? m->m_size : new_size;
  1944.  
  1945.         for (p = m->m_memory; p < & m->m_memory[ min_size ]; p++) {
  1946.                 if (*p != m->m_pattern)
  1947.                         corrupted ();
  1948.         }
  1949.  
  1950.         m->m_size = new_size;
  1951.         for (p = m->m_memory; p < & m->m_memory[ m->m_size ]; p++)
  1952.                 *p = m->m_pattern;
  1953.  
  1954.  
  1955.         add_to_events (m);
  1956. } /* realloc_event */
  1957.  
  1958. /*
  1959.  * add_to_events (m)
  1960.  *
  1961.  * Add the given event structure onto the time-ordered event list.
  1962.  */
  1963.  
  1964. add_to_events (m)
  1965. register struct memevent *m;
  1966. {
  1967.         register struct memevent *l;
  1968.         register struct memevent *ol;
  1969.  
  1970.         for (ol = NULL, l = events; l != NULL; ol = l, l = l->m_next) {
  1971.                 if (l->m_time > m->m_time) {
  1972.                         if (ol == NULL) {
  1973.                                 m->m_next = events;
  1974.                                 events = m;
  1975.                         }
  1976.                         else {
  1977.                                 m->m_next = l;
  1978.                                 ol->m_next = m;
  1979.                         }
  1980.  
  1981.                         l->m_time -= m->m_time;
  1982.                         return;
  1983.                 }
  1984.  
  1985.                 m->m_time -= l->m_time;
  1986.         }
  1987.  
  1988.         if (events == NULL)
  1989.                 events = m;
  1990.         else
  1991.                 ol->m_next = m;
  1992. } /* add_to_events */
  1993.  
  1994. /*
  1995.  * init_events ()
  1996.  *
  1997.  * Set up the memevent pools.
  1998.  */
  1999.  
  2000. init_events ()
  2001. {
  2002.         register struct memevent *m;
  2003.         int i;
  2004.  
  2005.         for (i = 0, m = eventpool; m < & eventpool[ MAX_EVENTS ]; m++, i++) {
  2006.                 m->m_id = i;
  2007.                 m->m_next = m + 1;
  2008.         }
  2009.  
  2010.         eventpool[ MAX_EVENTS-1 ].m_next = NULL;
  2011.  
  2012.         free_events = eventpool;
  2013. }
  2014.  
  2015. /*
  2016.  * init (argc, argv)
  2017.  *
  2018.  * Initialize the memory tests.
  2019.  */
  2020.  
  2021. init (argc, argv)
  2022. int argc;
  2023. char *argv[];
  2024. {
  2025.     if (argc != 4) {
  2026.         fprintf (stderr, "usage: %s new_prob time_to_go stat_freq\n", argv[ 0 ]);
  2027.         exit (1);
  2028.     }
  2029.         new_probability = atoi (argv[ 1 ]);
  2030.         time_to_go = atoi (argv[ 2 ]);
  2031.         stat_frequency = atoi (argv[ 3 ]);
  2032.  
  2033.         srandom (1);
  2034.  
  2035.         init_events ();
  2036.  
  2037.         /*
  2038.          * Use statically allocated buffers, otherwise
  2039.          * stdio() will call malloc to allocate buffers, and
  2040.          * this gets confusing when debugging stuff.
  2041.          */
  2042.  
  2043.         setbuf (stdout, (char *) NULL);
  2044.         setbuf (stderr, (char *) NULL);
  2045. }
  2046.  
  2047. /*
  2048.  * XXX: Should really send SIGQUIT ...
  2049.  */
  2050.  
  2051. cause_core_dump ()
  2052. {
  2053.         * (long *) 1 = 5;
  2054. }
  2055.  
  2056. corrupted ()
  2057. {
  2058.         printf ("Corrupted\n");
  2059.         cause_core_dump ();
  2060. }
  2061.  
  2062. out_of_memory ()
  2063. {
  2064.         printf ("Out of memory!\n");
  2065.         cause_core_dump ();
  2066. }
  2067.  
  2068. /*
  2069.  * odds (m, n)
  2070.  *
  2071.  * Return TRUE (non-zero) with probability m out of n.
  2072.  */
  2073.  
  2074. odds (m, n)
  2075. int m;
  2076. int n;
  2077. {
  2078.         return ((random () % n) < m);
  2079. }
  2080.  
  2081. /*
  2082.  * random_range (lo, hi)
  2083.  *
  2084.  * Pick a random integer from lo to hi (inclusive).
  2085.  */
  2086.  
  2087. random_range (lo, hi)
  2088. int lo;
  2089. int hi;
  2090. {
  2091.         return ((random () % (hi - lo + 1)) + lo);
  2092. }
  2093.  
  2094. #if DBG
  2095. /*
  2096.  * de_cmpf (m1,m2)
  2097.  *
  2098.  * compare function for qsort() in dump_events.
  2099.  * Sort by memory address of the memory allocated to
  2100.  * the event.
  2101.  */
  2102.  
  2103. int
  2104. de_cmpf (m1, m2)
  2105. struct memevent **m1;
  2106. struct memevent **m2;
  2107. {
  2108.         unsigned long maddr1 = (unsigned long) (*m1)->m_memory;
  2109.         unsigned long maddr2 = (unsigned long) (*m2)->m_memory;
  2110.  
  2111.                                         /* sloppy */
  2112.         return (maddr1 - maddr2);
  2113. }
  2114. #endif DBG
  2115.  
  2116. /*
  2117.  * dump_events ()
  2118.  *
  2119.  * Useful for debugging.
  2120.  */
  2121.  
  2122. #if DBG
  2123. dump_events ()
  2124. {
  2125.         static struct memevent *sorted[ MAX_EVENTS ];
  2126.         register struct memevent *m;
  2127.         register int i;
  2128.  
  2129.         fprintf (stderr, "DUMP EVENTS (time remaining = %d)\n", time_to_go);
  2130.  
  2131.         for (m = events, i = 0; m != NULL; m = m->m_next, i++)
  2132.                 sorted[ i ] = m;
  2133.  
  2134.         if (i == 0) {
  2135.                 fprintf (stderr, "No events.\n");
  2136.                 return;
  2137.         }
  2138.  
  2139.         qsort ((char *) sorted, i, sizeof (struct memevent *), de_cmpf);
  2140.  
  2141.         sorted[ i ] = 0;
  2142.         for (i = 0, m = sorted[ 0 ]; m != NULL; m = sorted[ ++i ]) {
  2143.                 fprintf (stderr, "E# %3d: ", m->m_id);
  2144.                 fprintf (stderr, "SIZ%4d, ", m->m_size);
  2145.                 fprintf (stderr, "RANGE: 0x%08x -- 0x%08x ",
  2146.                                 m->m_memory, m->m_memory + m->m_size - 1);
  2147.                 (void) fflush (stderr);
  2148.  
  2149.                                         /* Peek at the surrounding longs,
  2150.                                            for debugging a particular malloc
  2151.                                            implementation.  Your choices may
  2152.                                            vary. */
  2153.  
  2154.                 fprintf (stderr, "BOUNDARY TAGS: %4d ", * (long *) (m->m_memory - 4));
  2155.                 (void) fflush (stderr);
  2156.                 fprintf (stderr, "%4d\n", * (long *) ((m->m_memory - 8) - (* (long *) (m->m_memory - 4))));
  2157.                 (void) fflush (stderr);
  2158.         }
  2159.         fprintf (stderr, "END DUMP_EVENTS\n");
  2160.         (void) fflush (stderr);
  2161. } /* dump_events */
  2162. #endif DBG
  2163. @@@End of mtest2.c
  2164. echo x - mtest3.c 1>&2
  2165. cat >mtest3.c <<'@@@End of mtest3.c'
  2166. /* NOT copyright by SoftQuad Inc. -- msb, 1988 */
  2167. #ifndef lint
  2168. static char *SQ_SccsId = "@(#)mtest3.c    1.2 88/08/25";
  2169. #endif
  2170. #include <stdio.h>
  2171. /*
  2172. ** looptest.c -- intensive allocator tester 
  2173. **
  2174. ** Usage:  looptest
  2175. **
  2176. ** History:
  2177. **    4-Feb-1987 rtech!daveb 
  2178. */
  2179.  
  2180.  
  2181. # ifdef SYS5
  2182. # define random    rand
  2183. # else
  2184. # include <sys/vadvise.h>
  2185. # endif
  2186.  
  2187. # include <stdio.h>
  2188. # include <signal.h>
  2189. # include <setjmp.h>
  2190.  
  2191. # define MAXITER    1000000        /* main loop iterations */
  2192. # define MAXOBJS    1000        /* objects in pool */
  2193. # define BIGOBJ        90000        /* max size of a big object */
  2194. # define TINYOBJ    80        /* max size of a small object */
  2195. # define BIGMOD        100        /* 1 in BIGMOD is a BIGOBJ */
  2196. # define STATMOD    10000        /* interation interval for status */
  2197.  
  2198. main( argc, argv )
  2199. int argc;
  2200. char **argv;
  2201. {
  2202.     register int **objs;        /* array of objects */
  2203.     register int *sizes;        /* array of object sizes */
  2204.     register int n;            /* iteration counter */
  2205.     register int i;            /* object index */
  2206.     register int size;        /* object size */
  2207.     register int r;            /* random number */
  2208.  
  2209.     int objmax;            /* max size this iteration */
  2210.     int cnt;            /* number of allocated objects */
  2211.     int nm = 0;            /* number of mallocs */
  2212.     int nre = 0;            /* number of reallocs */
  2213.     int nal;            /* number of allocated objects */
  2214.     int nfre;            /* number of free list objects */
  2215.     long alm;            /* memory in allocated objects */
  2216.     long frem;            /* memory in free list */
  2217.     long startsize;            /* size at loop start */
  2218.     long endsize;            /* size at loop exit */
  2219.     long maxiter = 0;        /* real max # iterations */
  2220.  
  2221.     extern char end;        /* memory before heap */
  2222.     char *calloc();
  2223.     char *malloc();
  2224.     char *sbrk();
  2225.     long atol();
  2226.  
  2227. # ifndef SYS5
  2228.     /* your milage may vary... */
  2229.     vadvise( VA_ANOM );
  2230. # endif
  2231.  
  2232.     if (argc > 1)
  2233.         maxiter = atol (argv[1]);
  2234.     if (maxiter <= 0)
  2235.         maxiter = MAXITER;
  2236.  
  2237.     printf("MAXITER %d MAXOBJS %d ", maxiter, MAXOBJS );
  2238.     printf("BIGOBJ %d, TINYOBJ %d, nbig/ntiny 1/%d\n",
  2239.     BIGOBJ, TINYOBJ, BIGMOD );
  2240.     fflush( stdout );
  2241.  
  2242.     if( NULL == (objs = (int **)calloc( MAXOBJS, sizeof( *objs ) ) ) )
  2243.     {
  2244.         fprintf(stderr, "Can't allocate memory for objs array\n");
  2245.         exit(1);
  2246.     }
  2247.  
  2248.     if( NULL == ( sizes = (int *)calloc( MAXOBJS, sizeof( *sizes ) ) ) )
  2249.     {
  2250.         fprintf(stderr, "Can't allocate memory for sizes array\n");
  2251.         exit(1);
  2252.     }
  2253.  
  2254.     /* as per recent discussion on net.lang.c, calloc does not 
  2255.     ** necessarily fill in NULL pointers...
  2256.     */
  2257.     for( i = 0; i < MAXOBJS; i++ )
  2258.         objs[ i ] = NULL;
  2259.  
  2260.     startsize = sbrk(0) - &end;
  2261.     printf( "Memory use at start: %d bytes\n", startsize );
  2262.     fflush(stdout);
  2263.  
  2264.     printf("Starting the test...\n");
  2265.     fflush(stdout);
  2266.     for( n = 0; n < maxiter ; n++ )
  2267.     {
  2268.         if( !(n % STATMOD) )
  2269.         {
  2270.             printf("%d iterations\n", n);
  2271.             fflush(stdout);
  2272.         }
  2273.  
  2274.         /* determine object of interst and it's size */
  2275.  
  2276.         r = random();
  2277.         objmax = ( r % BIGMOD ) ? TINYOBJ : BIGOBJ;
  2278.         size = r % objmax;
  2279.         i = r % (MAXOBJS - 1);
  2280.  
  2281.         /* either replace the object of get a new one */
  2282.  
  2283.         if( objs[ i ] == NULL )
  2284.         {
  2285.             objs[ i ] = (int *)malloc( size );
  2286.             nm++;
  2287.         }
  2288.         else
  2289.         {
  2290.             /* don't keep bigger objects around */
  2291.             if( size > sizes[ i ] )
  2292.             {
  2293.                 objs[ i ] = (int *)realloc( objs[ i ], size );
  2294.                 nre++;
  2295.             }
  2296.             else
  2297.             {
  2298.                 free( objs[ i ] );
  2299.                 objs[ i ] = (int *)malloc( size );
  2300.                 nm++;
  2301.             }
  2302.         }
  2303.  
  2304.         sizes[ i ] = size;
  2305.         if( objs[ i ] == NULL )
  2306.         {
  2307.             printf("\nCouldn't allocate %d byte object!\n", 
  2308.                 size );
  2309.             break;
  2310.         }
  2311.     } /* for() */
  2312.  
  2313.     printf( "\n" );
  2314.     cnt = 0;
  2315.     for( i = 0; i < MAXOBJS; i++ )
  2316.         if( objs[ i ] )
  2317.             cnt++;
  2318.  
  2319.     printf( "Did %d iterations, %d objects, %d mallocs, %d reallocs\n",
  2320.         n, cnt, nm, nre );
  2321.     printf( "Memory use at end: %d bytes\n", sbrk(0) - &end );
  2322.     fflush( stdout );
  2323.  
  2324.     /* free all the objects */
  2325.     for( i = 0; i < MAXOBJS; i++ )
  2326.         if( objs[ i ] != NULL )
  2327.             free( objs[ i ] );
  2328.  
  2329.     endsize = sbrk(0) - &end;
  2330.     printf( "Memory use after free: %d bytes\n", endsize );
  2331.     fflush( stdout );
  2332.  
  2333.     if( startsize != endsize )
  2334.         printf("startsize %d != endsize %d\n", startsize, endsize );
  2335.  
  2336.     free( objs );
  2337.     free( sizes );
  2338.  
  2339.     exit( 0 );
  2340. }
  2341.  
  2342. @@@End of mtest3.c
  2343. echo x - realloc.c 1>&2
  2344. cat >realloc.c <<'@@@End of realloc.c'
  2345. #include "malloc.h"
  2346. #define NULL 0
  2347.  
  2348. /* NOT copyright by SoftQuad. - msb, 1988 */
  2349. #ifndef lint
  2350. static char *SQ_SccsId = "@(#)realloc.c    1.7 88/08/24";
  2351. #endif
  2352. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2353.  *  realloc                William L. Sebok
  2354.  * A  "smarter" malloc v1.0        Sept. 24, 1984 rev. Oct 17,1986
  2355.  *            Then modified by Arthur David Olsen
  2356.  *            MALLOCTRACE added by Mark Brader
  2357.  *
  2358.  *    realloc takes previously malloc-allocated area at mem, and tries
  2359.  *     to change its size to nbytes bytes, moving it and copying its
  2360.  *     contents if necessary.
  2361.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  2362.  
  2363. #ifdef    MALLOCTRACE    /* See ./TRACE_README */
  2364. unsigned old_nbytes;
  2365. #endif
  2366.  
  2367. char *
  2368. realloc(mem,nbytes)
  2369. register char *mem; unsigned nbytes;    /* for 4.3 compat. */
  2370.  
  2371. #ifdef    MALLOCTRACE
  2372.     /*
  2373.      * The (real) realloc function may call malloc or not; we want
  2374.      * to generate a trace message from here if it doesn't.  And
  2375.      * likewise for free.  Since the function is somewhat complicated,
  2376.      * this goal is most easily achieved by wrapping a dummy realloc
  2377.      * function -- this one -- around the real realloc.  The real
  2378.      * realloc is imaginatively renamed real_realloc.
  2379.      */
  2380. {
  2381.  
  2382.     char *real_realloc(), *newmem;
  2383.     Size new_nbytes;
  2384.     extern enum _malstate _malstate;
  2385.  
  2386. #define    BYTES(mem)    (((struct overhead *)(mem - sizeof(struct overhead))) \
  2387.         ->ov_length)    /* How realloc finds the allocated length */
  2388.  
  2389.     old_nbytes = 0;        /* Normally changed in real_realloc */
  2390.  
  2391.     if (_malstate == S_INITIAL) _mal_init_trace();
  2392.  
  2393.     if (_malstate == S_TRACING)
  2394.         _malstate = S_IN_REALLOC;
  2395.  
  2396.     newmem = real_realloc (mem, nbytes);
  2397.  
  2398.     if (_malstate == S_IN_REALLOC) {
  2399.         _malstate = S_TRACING;
  2400.  
  2401.         if (newmem) new_nbytes = BYTES (newmem);
  2402.         _mal_write_trace ("realloc", (Size) old_nbytes,
  2403.                         (Size) old_nbytes, mem);
  2404.         _mal_write_trace ("realloc-to", (Size) nbytes,
  2405.                         (Size) new_nbytes, newmem);
  2406.     }
  2407.  
  2408.     return newmem;
  2409. }
  2410.  
  2411.     /*
  2412.      * And now, the real realloc.  If MALLOCTRACE is not defined,
  2413.      * this function will of course compile as realloc.
  2414.      */
  2415.  
  2416. static char *
  2417. real_realloc(mem,nbytes)
  2418. register char *mem; unsigned nbytes;
  2419.  
  2420. #endif
  2421. {
  2422.     register char *newmem = NULL;
  2423.     register struct overhead *p;
  2424.     Size surplus, length;
  2425.     Size oldlength;
  2426.  
  2427.     if (mem == NULL)
  2428.         return(malloc(nbytes));
  2429.  
  2430.     /* if beyond current arena it has to be bad */
  2431.     if (mem > (char*)FROMADJ(adjhead.q_back) + sizeof(struct overhead))
  2432.         return(NULL);
  2433.     
  2434.     p = (struct overhead *)(mem - sizeof(struct overhead));
  2435.  
  2436.     if (p->ov_magic != MAGIC_BUSY && p->ov_magic != MAGIC_FREE)
  2437.         return(NULL);    /* already gone */
  2438.  
  2439.     oldlength = p->ov_length;
  2440.  
  2441. #ifdef    MALLOCTRACE
  2442.     old_nbytes = oldlength;
  2443. #endif
  2444.  
  2445.     nbytes = ((nbytes + (NALIGN-1)) & (~(NALIGN-1)))
  2446.          + sizeof(struct overhead);
  2447.  
  2448.     if (p->ov_magic == MAGIC_BUSY) {
  2449.         /* free may claim adjacent free memory, compacting storage */
  2450.         char oendfree = endfree;
  2451.         endfree = 0;
  2452.         free(mem);    /* free it but don't let it contract break */
  2453.         endfree = oendfree;
  2454.         if (p->ov_magic != MAGIC_FREE) {    /* check if moved */
  2455.             p = FROMADJ(p->ov_adj.q_back);
  2456.             newmem = (char *)p + sizeof(struct overhead);
  2457.         }
  2458.     }
  2459.  
  2460.     /* at this point p->ov_magic should be MAGIC_FREE */
  2461.     ASSERT(p->ov_magic == MAGIC_FREE, "\nrealloc: bad magic number.\n");
  2462.  
  2463.     /*
  2464.     ** We wait to set length until after any possible compaction.
  2465.     */
  2466.     length = p->ov_length;
  2467.     surplus = length - nbytes;
  2468.     if (surplus >= 0) {
  2469.         /* present location large enough */
  2470.         remque(TOBUK(p));
  2471.         p->ov_magic = MAGIC_BUSY;
  2472.     } else if ( ((char *)p + p->ov_length) == CURBRK) {
  2473.         /* if at break, grow in place */
  2474.         (void) BRK((char *)p + nbytes);
  2475.         p->ov_length = nbytes;
  2476.         remque(TOBUK(p));
  2477.         p->ov_magic = MAGIC_BUSY;
  2478.     } else {
  2479.         newmem = malloc(nbytes - sizeof(struct overhead));
  2480.         if (newmem == NULL)
  2481.             return(NULL);
  2482.         surplus = 0;
  2483.     }
  2484.  
  2485.     /* if returned address is different, move data */
  2486.     if (newmem != NULL) {
  2487.         /* note: it is assumed that bcopy does the right thing on
  2488.          * overlapping extents (true on the vax)
  2489.          */
  2490.         (void)bcopy(mem, newmem,
  2491.             ((oldlength < nbytes) ? oldlength : nbytes) -
  2492.                 sizeof(struct overhead));
  2493.          mem = newmem;
  2494.     }
  2495.  
  2496.     /* if more memory than we need then return excess to buckets */
  2497.     if (surplus > (int) sizeof(struct overhead)) {
  2498.         register struct overhead *q;
  2499.         q = (struct overhead *)( (char *)p + nbytes);
  2500.         q->ov_length = surplus;
  2501.         q->ov_magic = MAGIC_FREE;
  2502.         insque(TOADJ(q),TOADJ(p));
  2503.         {
  2504.             register struct qelem *    bp;
  2505.  
  2506.             bp = &buckets[mlindx(surplus)];
  2507.             if (bp > hifreebp)
  2508.                 hifreebp = bp;
  2509.             insque(TOBUK(q),bp);
  2510.         }
  2511.         p->ov_length -= surplus;
  2512.     }
  2513.  
  2514.     if (endfree)
  2515.         mlfree_end();
  2516.  
  2517.     return(mem);
  2518. }
  2519. @@@End of realloc.c
  2520. echo x - write_trace.c 1>&2
  2521. cat >write_trace.c <<'@@@End of write_trace.c'
  2522. #ifdef    MALLOCTRACE
  2523.  
  2524.  
  2525. /* NOT copyright by SoftQuad. - msb, 1988 */
  2526. #ifndef lint
  2527. static char *SQ_SccsId = "@(#)write_trace.c    1.4 88/08/24";
  2528. #endif
  2529. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2530.  *  _mal_write_trace                See ./ORIGINS for credits
  2531.  *
  2532.  *     _mal_write_trace writes a line to the malloc trace file.
  2533.  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
  2534.  
  2535. #include    <stdio.h>
  2536. #include    "malloc.h"
  2537.  
  2538. /* Machine-dependent stuff:  the Sun's stack format. */
  2539.  
  2540. struct    stackframe {
  2541.     struct stackframe    *link;
  2542.     char            *ret_addr;
  2543. };
  2544.  
  2545. typedef struct stackframe    *FRAMEPTR;
  2546.  
  2547. #define    MYFRAME(myfirstarg)     ((FRAMEPTR) (((Size *) &(myfirstarg)) - 2))
  2548.  
  2549. #define    NEXTFRAME(myframe)    ((myframe)->link)
  2550. #define    RET_ADDR(myframe)    ((myframe)->ret_addr)
  2551.  
  2552. /* Test whether a stdio file is still writable */
  2553.  
  2554. #define    STDIO_WRITABLE(fp)    (((fp)->_flag & _IOWRT) != NULL)
  2555.  
  2556.  
  2557. void
  2558. _mal_write_trace (event_label, req_nbytes, act_nbytes, mem)
  2559. char *event_label;
  2560. Size req_nbytes, act_nbytes;
  2561. char *mem;
  2562. {
  2563.     extern enum _malstate _malstate;
  2564.     extern FILE *_malfp;
  2565.     extern int _malbuff;
  2566.     FRAMEPTR frame;
  2567.  
  2568.     if (_malstate != S_TRACING || !STDIO_WRITABLE(_malfp))
  2569.         return;
  2570.  
  2571.     /* Reset the state in case stdio does any mallocing */
  2572.     _malstate = S_IN_STDIO;
  2573.  
  2574.     if (req_nbytes == act_nbytes)
  2575.         fprintf (_malfp, "%s of %ld at %ld\n",
  2576.             event_label, (long) req_nbytes, (long) mem);
  2577.     else
  2578.         fprintf (_malfp, "%s of %ld gets %ld at %ld\n",
  2579.             event_label, (long) req_nbytes, (long) act_nbytes,
  2580.                                 (long) mem);
  2581.  
  2582.     for (frame = NEXTFRAME (MYFRAME (event_label));
  2583.             frame;
  2584.             frame = NEXTFRAME (frame))
  2585.             
  2586.         fprintf (_malfp, "caller %8.8lx\n", (long) RET_ADDR (frame));
  2587.  
  2588.     fprintf (_malfp, "\n");
  2589.  
  2590.     /* Flush if desired */
  2591.     if (!_malbuff) fflush (_malfp);
  2592.  
  2593.     /* And back to normal */
  2594.     _malstate = S_TRACING;
  2595. }
  2596. #endif
  2597. @@@End of write_trace.c
  2598. echo x - Makefile 1>&2
  2599. cat >Makefile <<'@@@End of Makefile'
  2600. #
  2601. #    SQ sccsid @(#)Makefile    1.4 88/08/25
  2602. #    NOT copyright by SoftQuad.  - msb, 1988
  2603. #
  2604. # This is configured to make the traced version of malloc; see mallck(1)
  2605. # and ./TRACE_README.  To make the regular version, delete -DMALLOCTRACE.
  2606. #                            Mark Brader
  2607. #
  2608.  
  2609. CARGS= -O -DMALLOCTRACE
  2610.  
  2611. MALLOC_C    = malloc.c free.c realloc.c forget.c write_trace.c init_trace.c
  2612. MALLOC_O    = malloc.o free.o realloc.o forget.o write_trace.o init_trace.o
  2613.  
  2614. all:    malloctrace.a
  2615.  
  2616. mtests:    mtest1 mtest2 mtest3
  2617.  
  2618. install: malloctrace.a
  2619.     mv malloctrace.a /usr/lib/malloctrace.a
  2620.     
  2621. .c.o:    $*.c
  2622.     ${CC} -c ${CARGS} $*.c
  2623.  
  2624. $(MALLOC_O):    malloc.h
  2625.  
  2626. malloctrace.a:    $(MALLOC_O)
  2627.     ar rv malloctrace.a $(MALLOC_O)
  2628.     ranlib malloctrace.a
  2629.  
  2630. mtest1:    mtest1.c
  2631.  
  2632. mtest2:    mtest2.c
  2633.  
  2634. mtest3:    mtest3.c
  2635.  
  2636. mtest1 mtest2 mtest3:    malloctrace.a
  2637.     ${CC} -O $@.c malloctrace.a -o $@
  2638.  
  2639. clean:
  2640.     rm -f *.o tstmalloc core
  2641. @@@End of Makefile
  2642. exit 0
  2643. -- 
  2644. Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
  2645.