home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume27 / efence / part01 < prev    next >
Encoding:
Text File  |  1993-09-01  |  57.5 KB  |  2,001 lines

  1. Newsgroups: comp.sources.unix
  2. From: bruce@pixar.com (Bruce Perens)
  3. Subject: v27i026: efence - Electric Fence, a debugging malloc() library, Part01/01
  4. Message-id: <1.746912952.24065@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: bruce@pixar.com (Bruce Perens)
  9. Posting-Number: Volume 27, Issue 26
  10. Archive-Name: efence/part01
  11.  
  12. Electric Fence is a different kind of malloc() debugger. It uses the virtual
  13. memory hardware of your system to detect when software overruns the boundaries
  14. of a malloc() buffer. It will also detect any accesses of memory that has
  15. been released by free(). Because it uses the VM hardware for detection,
  16. Electric Fence stops your program on the first instruction that causes
  17. a bounds violation. It's then trivial to use a debugger to display the
  18. offending statement.
  19.  
  20. This version will run on:
  21.     All System V Revision 4 platforms (and possibly earlier revisions)
  22.     including:
  23.         Every 386 System V I've heard of.
  24.         Solaris 2.x
  25.         SGI IRIX 5.0 (but not 4.x)
  26.  
  27.     IBM AIX on the RS/6000.
  28.     SunOS 4.X (using an ANSI C compiler and probably static linking).
  29.  
  30.     HP/UX 9.01, and possibly earlier versions.
  31.  
  32. The software license and complete information on its use are in the man
  33. page: libefence.3 .
  34.  
  35.     bruce@pixar.com (Bruce Perens)
  36.  
  37. #! /bin/sh
  38. # This is a shell archive.  Remove anything before this line, then unpack
  39. # it by saving it into a file and typing "sh file".  To overwrite existing
  40. # files, type "sh file -c".  You can also feed this as standard input via
  41. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  42. # will see the following message at the end:
  43. #        "End of shell archive."
  44. # Contents:  README libefence.3 Makefile efence.h efence.c page.c
  45. #   print.c eftest.c tstheap.c
  46. # Wrapped by bruce@mongo on Wed Sep  1 11:20:56 1993
  47. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  48. if test -f 'README' -a "${1}" != "-c" ; then 
  49.   echo shar: Will not clobber existing file \"'README'\"
  50. else
  51. echo shar: Extracting \"'README'\" \(1410 characters\)
  52. sed "s/^X//" >'README' <<'END_OF_FILE'
  53. XThis is Electric Fence 2.0.1
  54. X
  55. XElectric Fence is a different kind of malloc() debugger. It uses the virtual
  56. Xmemory hardware of your system to detect when software overruns the boundaries
  57. Xof a malloc() buffer. It will also detect any accesses of memory that has
  58. Xbeen released by free(). Because it uses the VM hardware for detection,
  59. XElectric Fence stops your program on the first instruction that causes
  60. Xa bounds violation. It's then trivial to use a debugger to display the
  61. Xoffending statement.
  62. X
  63. XThis version will run on:
  64. X    All System V Revision 4 platforms (and possibly earlier revisions)
  65. X    including:
  66. X        Every 386 System V I've heard of.
  67. X        Solaris 2.x
  68. X        SGI IRIX 5.0 (but not 4.x)
  69. X
  70. X    IBM AIX on the RS/6000.
  71. X
  72. X    SunOS 4.X (using an ANSI C compiler and probably static linking).
  73. X
  74. X    HP/UX 9.01, and possibly earlier versions.
  75. X
  76. XOn some of these platforms, you'll have to uncomment lines in the Makefile
  77. Xthat apply to your particular system.
  78. X
  79. XIf you test Electric Fence on a platform not mentioned here, please send me a
  80. Xreport.
  81. X
  82. XIt will probably port to any ANSI/POSIX system that provides mmap(), and
  83. Xmprotect(), as long as mprotect() has the capability to turn off all access
  84. Xto a memory page, and mmap() can use /dev/zero or the MAP_ANONYMOUS flag
  85. Xto create virtual memory pages.
  86. X
  87. XThe software license and complete information on its use are in the man
  88. Xpage: libefence.3 .
  89. X
  90. X    Thanks
  91. X
  92. X    Bruce Perens
  93. X    Bruce@Pixar.com
  94. END_OF_FILE
  95. if test 1410 -ne `wc -c <'README'`; then
  96.     echo shar: \"'README'\" unpacked with wrong size!
  97. fi
  98. # end of 'README'
  99. fi
  100. if test -f 'libefence.3' -a "${1}" != "-c" ; then 
  101.   echo shar: Will not clobber existing file \"'libefence.3'\"
  102. else
  103. echo shar: Extracting \"'libefence.3'\" \(14508 characters\)
  104. sed "s/^X//" >'libefence.3' <<'END_OF_FILE'
  105. X.TH efence 3 27-April-1993
  106. X.SH NAME
  107. Xefence \- Electric Fence Malloc Debugger
  108. X.SH SYNOPSIS
  109. X.nf
  110. X.ft B
  111. X#include <stdlib.h>
  112. X.ft
  113. X.fi
  114. X.LP
  115. X.nf
  116. X.ft B
  117. Xvoid * malloc (size_t size);
  118. X.ft
  119. X.fi
  120. X.LP
  121. X.nf
  122. X.ft B
  123. Xvoid free (void *ptr);
  124. X.ft
  125. X.fi
  126. X.LP
  127. X.nf
  128. X.ft B
  129. Xvoid * realloc (void *ptr, size_t size);
  130. X.ft
  131. X.fi
  132. X.LP
  133. X.nf
  134. X.ft B
  135. Xvoid * calloc (size_t nelem, size_t elsize);
  136. X.ft
  137. X.fi
  138. X.LP
  139. X.nf
  140. X.ft B
  141. Xvoid * memalign (size_t alignment, size_t size);
  142. X.ft
  143. X.fi
  144. X.LP
  145. X.nf
  146. X.ft B
  147. Xvoid * valloc (size_t size);
  148. X.ft
  149. X.fi
  150. X.LP
  151. X.nf
  152. X.ft B
  153. Xextern int EF_ALIGNMENT;
  154. X.ft
  155. X.fi
  156. X.LP
  157. X.nf
  158. X.ft B
  159. Xextern int EF_PROTECT_BELOW;
  160. X.ft
  161. X.fi
  162. X.LP
  163. X.nf
  164. X.ft B
  165. Xextern int EF_PROTECT_FREE;
  166. X.ft
  167. X.fi
  168. X.SH DESCRIPTION
  169. X.I Electric Fence
  170. Xhelps you detect two common programming bugs:
  171. Xsoftware that overruns the boundaries of a malloc() memory
  172. Xallocation, and software that touches a memory allocation that has been
  173. Xreleased by free(). Unlike other malloc() debuggers, Electric Fence will
  174. Xdetect
  175. X.I read
  176. Xaccesses as well as writes, and it will pinpoint the exact instruction that
  177. Xcauses an error. It has been in use at Pixar since 1987, and at many other
  178. Xsites for years.
  179. X.LP
  180. XElectric Fence uses the virtual memory hardware of your computer to place an
  181. Xinaccessible memory page immediately after (or before, at the user's option)
  182. Xeach memory allocation. When software reads or writes this inaccessible page,
  183. Xthe
  184. Xhardware issues a segmentation fault, stopping the program at the offending
  185. Xinstruction. It is then trivial to find the erroneous statement using your
  186. Xfavorite debugger. In a similar manner, memory that has been released by
  187. Xfree() is made inaccessible, and any code that touches it will get a
  188. Xsegmentation fault.
  189. X.LP
  190. XSimply linking your application with libefence.a will allow you to detect
  191. Xmost, but not all, malloc buffer overruns and accesses of free memory.
  192. XIf you want to be reasonably sure that you've found
  193. X.I all
  194. Xbugs of this type, you'll have to read and understand the rest of this
  195. Xman page.
  196. X.SH USAGE
  197. XLink your program with the library
  198. X.B libefence.a .
  199. XMake sure you are
  200. X.I not
  201. Xlinking with
  202. X.B -lmalloc,
  203. X.B -lmallocdebug,
  204. Xor with other malloc-debugger or malloc-enhancer libraries.
  205. XYou can only use one at a time.
  206. XIf your system administrator
  207. Xhas installed Electric Fence for public use, you'll be able to use the
  208. X.B -lefence
  209. Xargument to the linker, otherwise you'll have to put the path-name for
  210. X.B libefence.a
  211. Xin the linker's command line.
  212. XSome systems will require special arguments to the linker to assure that
  213. Xyou are using the Electric Fence malloc() and not the one from your C library.
  214. XOn AIX systems, you may have to use the flags
  215. X.br
  216. X.B -bnso
  217. X.B -bnodelcsect
  218. X.B -bI:/lib/syscalls.exp
  219. X.br
  220. XOn Sun systems running SunOS 4.X, you'll probably have to use
  221. X.B -Bstatic.
  222. X.LP
  223. XRun your program
  224. X.I using a debugger. 
  225. XIt's easier to work this way than to create a
  226. X.B core
  227. Xfile and post-mortem debug it. Electric Fence can create
  228. X.I huge
  229. Xcore files, and some operating systems will thus take minutes simply to dump
  230. Xcore! Some operating systems will not create usable core files from programs
  231. Xthat are linked with Electric Fence.
  232. XIf your program has one of the errors detected by Electric Fence, it will
  233. Xget a segmentation fault (SIGSEGV) at the offending instruction. Use the
  234. Xdebugger to locate the erroneous statement, and repair it.
  235. X.SH GLOBAL AND ENVIRONMENT VARIABLES
  236. XElectric Fence has four configuration switches that can be enabled via
  237. Xthe shell environment, or by setting the value of global integer variables
  238. Xusing a debugger. These switches change what bugs Electric Fence will detect,
  239. Xso it's important that you know how to use them.
  240. X.TP
  241. XEF_ALIGNMENT
  242. XThis is an integer that specifies the alignment for any memory allocations
  243. Xthat will be returned by malloc(), calloc(), and realloc().
  244. XThe value is specified in
  245. Xbytes, thus a value of 4 will cause memory to be aligned to 32-bit boundaries
  246. Xunless your system doesn't have a 8-bit characters. EF_ALIGNMENT is set to
  247. Xsizeof(int) by default, since that is generally the word-size of your CPU.
  248. XIf your program requires that allocations be aligned to 64-bit
  249. Xboundaries and you have a 32-bit
  250. X.B int
  251. Xyou'll have to set this value to 8. This is the case when compiling with the
  252. X.B -mips2
  253. Xflag on MIPS-based systems such as those from SGI.
  254. XThe memory allocation that is returned by Electric Fence malloc() is aligned
  255. Xusing the value in EF_ALIGNMENT, and
  256. X.I its size the multiple of
  257. X.I that value
  258. Xthat is greater than or equal to the requested size.
  259. XFor this reason, you will sometimes want to set EF_ALIGNMENT to 0 (no
  260. Xalignment), so that
  261. Xyou can detect overruns of less than your CPU's word size. Be sure to read
  262. Xthe section
  263. X.I WORD-ALIGNMENT AND OVERRUN DETECTION
  264. Xin this manual page before you try this.
  265. XTo change this value, set EF_ALIGNMENT in the shell environment to an
  266. Xinteger value, or assign
  267. Xto the global integer variable EF_ALIGNMENT using a debugger.
  268. X.TP
  269. XEF_PROTECT_BELOW
  270. XElectric Fence usually places an inaccessible page immediately after each
  271. Xmemory allocation, so that software that runs past the end of the allocation
  272. Xwill be detected. Setting EF_PROTECT_BELOW to 1 causes Electric Fence
  273. Xto place the inaccessible page
  274. X.I before
  275. Xthe allocation in the address space, so that under-runs will be detected
  276. Xinstead of over-runs.
  277. XWhen EF_PROTECT_BELOW is set, the EF_ALIGNMENT parameter is ignored.
  278. XAll allocations will be aligned to virtual-memory-page boundaries, and
  279. Xtheir size will be the exact size that was requested.
  280. XTo change this value, set EF_PROTECT_BELOW in the shell environment to an
  281. Xinteger value, or assign to the global integer variable EF_PROTECT_BELOW using
  282. Xa debugger.
  283. X.TP
  284. XEF_PROTECT_FREE
  285. XElectric Fence usually returns free memory to a pool from which it may be
  286. Xre-allocated. If you suspect that a program may be touching free memory,
  287. Xset EF_PROTECT_FREE to 1. This will cause Electric Fence to never re-allocate
  288. Xmemory once it has been freed, so that any access to free memory will be
  289. Xdetected. Some programs will use tremendous amounts of memory when this
  290. Xparameter is set.
  291. XTo change this value, set EF_PROTECT_FREE in the shell environment to an
  292. Xinteger value, or assign to the global integer variable EF_PROTECT_FREE using
  293. Xa debugger.
  294. X.TP
  295. XEF_ALLOW_MALLOC_0
  296. XBy default, Electric Fence traps calls to malloc() with a size of zero, because
  297. Xthey are often the result of a software bug. If EF_ALLOW_MALLOC_0 is non-zero,
  298. Xthe software will not trap calls to malloc() with a size of zero.
  299. XTo change this value, set EF_ALLOC_MALLOC_0 in the shell environment to an
  300. Xinteger value, or assign to the global integer variable EF_ALLOC_MALLOC_0 using
  301. Xa debugger.
  302. X.SH WORD-ALIGNMENT AND OVERRUN DETECTION
  303. XThere is a conflict between the alignment restrictions that malloc() operates
  304. Xunder and the debugging strategy used by Electric Fence. When detecting
  305. Xoverruns, Electric Fence malloc() allocates two or more virtual memory
  306. Xpages for each allocation. The last page is made inaccessible in such a way
  307. Xthat any read, write, or execute access will cause a segmentation fault.
  308. XThen, Electric Fence malloc() will return an address such that the first
  309. Xbyte after
  310. Xthe end of the allocation is on the inaccessible page.
  311. XThus, any overrun
  312. Xof the allocation will cause a segmentation fault.
  313. X.LP
  314. XIt follows that the
  315. Xaddress returned by malloc() is the address of the inaccessible page minus
  316. Xthe size of the memory allocation.
  317. XUnfortunately, malloc() is required to return
  318. X.I word-aligned
  319. Xallocations, since many CPUs can only access a word when its address is aligned.
  320. XThe conflict happens when software makes a memory allocation using a size that
  321. Xis not a multiple of the word size, and expects to do word accesses to that
  322. Xallocation. The location of the inaccessible page is fixed by hardware at
  323. Xa word-aligned address. If Electric Fence malloc() is to return an aligned
  324. Xaddress, it must increase the size of the allocation to a multiple of the
  325. Xword size.
  326. XIn addition, the functions memalign() and valloc() must honor explicit
  327. Xspecifications on the alignment of the memory allocation, and this, as well
  328. Xcan only be implemented by increasing the size of the allocation.
  329. XThus, there will be situations in which the end of a memory allocation
  330. Xcontains some padding space, and accesses of that padding space will not
  331. Xbe detected, even if they are overruns.
  332. X.LP
  333. XElectric Fence provides the variable EF_ALIGNMENT so that the user can
  334. Xcontrol the default alignment used by malloc(), calloc(), and realloc().
  335. XTo debug overruns as small as a single byte, you can set EF_ALIGNMENT to
  336. Xzero. This will result in Electric Fence malloc() returning unaligned
  337. Xaddresses for allocations with sizes that are not a multiple of the word
  338. Xsize. This is not a problem in most cases, because compilers must pad the
  339. Xsize of objects so that alignment restrictions are honored when storing
  340. Xthose objects in arrays. The problem surfaces when software allocates
  341. Xodd-sized buffers for objects that must be word-aligned. One case of this
  342. Xis software that allocates a buffer to contain a structure and a
  343. Xstring, and the string has an odd size (this example was in a popular TIFF
  344. Xlibrary). If word references are made to un-aligned buffers, you will see
  345. Xa bus error (SIGBUS) instead of a segmentation fault. The only way to fix
  346. Xthis is to re-write the offending code to make byte references or not make
  347. Xodd-sized allocations, or to set EF_ALIGNMENT to the word size.
  348. X.LP
  349. XAnother example of software incompatible with
  350. XEF_ALIGNMENT < word-size
  351. Xis the strcmp() function and other string functions on SunOS (and probably
  352. XSolaris), which make word-sized accesses to character strings, and may
  353. Xattempt to access up to three bytes beyond the end of a string. These
  354. Xresult in a segmentation fault (SIGSEGV). The only way around this is to
  355. Xuse versions of the string functions that perform byte references instead
  356. Xof word references.
  357. X.SH INSTRUCTIONS FOR DEBUGGING YOUR PROGRAM
  358. X.TP
  359. X1.
  360. XLink with libefence.a as explained above.
  361. X.TP
  362. X2.
  363. XRun your program in a debugger and fix any overruns or accesses to free memory.
  364. X.TP
  365. X3.
  366. XQuit the debugger.
  367. X.TP
  368. X4.
  369. XSet EF_PROTECT_BELOW = 1 in the shell environment.
  370. X.TP
  371. X5.
  372. XRepeat step 2, this time repairing underruns if they occur.
  373. X.TP
  374. X6.
  375. XQuit the debugger.
  376. X.TP
  377. X7.
  378. XRead the restrictions in the section on
  379. X.I WORD-ALIGNMENT AND OVERRUN DETECTION.
  380. XSee if you can
  381. Xset EF_ALIGNMENT to 0 and repeat step 2. Sometimes this will be too much work,
  382. Xor there will be problems with library routines for which you don't have the
  383. Xsource, that will prevent you from doing this.
  384. X.SH MEMORY USAGE AND EXECUTION SPEED
  385. XSince Electric Fence uses at least two virtual memory pages for each of its
  386. Xallocations, it's a terrible memory hog. I've sometimes found it necessary to
  387. Xadd a swap file using swapon(8) so that the system would have enough virtual
  388. Xmemory to debug my program. Also, the way we manipulate memory results in
  389. Xvarious cache and translation buffer entries being flushed with each call
  390. Xto malloc or free. The end result is that your program will be much slower
  391. Xand use more resources while you are debugging it with Electric Fence.
  392. X.LP
  393. XDon't leave libefence.a linked into production software! Use it only
  394. Xfor debugging.
  395. X.SH PORTING
  396. XElectric Fence is written for ANSI C. You should be able to port it with
  397. Xsimple changes to the Makefile and to page.c,
  398. Xwhich contains the memory management primitives .
  399. XMany POSIX platforms will require only a re-compile.
  400. XThe operating system facilities required to port Electric Fence are:
  401. X.IP
  402. XA way to allocate memory pages
  403. X.br
  404. XA way to make selected pages inaccessible.
  405. X.br
  406. XA way to make the pages accessible again.
  407. X.br
  408. XA way to detect when a program touches an inaccessible page.
  409. X.br
  410. XA way to print messages.
  411. X.LP
  412. XPlease e-mail me a copy of any changes you have to make, so that I can
  413. Xmerge them into the distribution.
  414. X.SH AUTHOR
  415. XBruce Perens
  416. X.SH WARNINGS
  417. XI have tried to do as good a job as I can on this software, but I doubt
  418. Xthat it is even theoretically possible to make it bug-free.
  419. XThis software has no warranty. It will not detect some bugs that you might
  420. Xexpect it to detect, and will indicate that some non-bugs are bugs.
  421. XBruce Perens and/or Pixar will not be liable to any claims resulting
  422. Xfrom the use of this software or the ideas within it.
  423. XThe entire responsibility for its use must
  424. Xbe assumed by the user. If you use it and it results in loss of life
  425. Xand/or property, tough. If it leads you on a wild goose chase and you waste
  426. Xtwo weeks debugging something, too bad.
  427. XIf you can't deal with the above, please don't use the software! I've written
  428. Xthis in an attempt to help other people, not to get myself sued or prosecuted.
  429. X.SH LICENSE
  430. XCopyright 1987,1988,1989,1990,1991,1992,1993 Bruce Perens.
  431. X.br
  432. XAll Rights Reserved except for those granted in this notice.
  433. X.br
  434. XPermission is granted for you to use this software to debug other programs.
  435. XYou may re-distribute it the original form in which I released it to you.
  436. XIf you make modifications to it, please send them to me for
  437. Xdistribution - you may not re-distribute modified versions.
  438. XYou may not sell this software. You may not sell support for this software.
  439. XIf you use ideas from this software in your own product, please pay me for
  440. Xthem.
  441. X.SH CONTACTING THE AUTHOR
  442. X.nf
  443. XBruce Perens
  444. Xc/o Pixar
  445. X1001 West Cutting Blvd., Suite 200
  446. XRichmond, CA 94804
  447. X
  448. XTelephone: 510-215-3502
  449. XFax: 510-236-0388
  450. XInternet: Bruce@Pixar.com
  451. X.fi
  452. X.ft
  453. X.SH FILES
  454. X/dev/zero: Source of memory pages (via mmap(2)).
  455. X.SH SEE ALSO
  456. Xmalloc(3), mmap(2), mprotect(2), swapon(8)
  457. X.SH DIAGNOSTICS
  458. XSegmentation Fault: Examine the offending statement for violation of the
  459. Xboundaries of a memory allocation.
  460. X.br
  461. XBus Error: See the section on
  462. X.I WORD-ALIGNMENT AND OVERRUN DETECTION.
  463. Xin this manual page.
  464. X.SH BUGS
  465. XMy explanation of the alignment issue could be improved.
  466. X.LP
  467. XSome Sun systems running SunOS 4.1 are reported to signal an access to a
  468. Xprotected page with
  469. X.B  SIGBUS
  470. Xrather than
  471. X.B SIGSEGV,
  472. XI suspect this is an undocumented feature of a particular Sun hardware
  473. Xversion, not just the operating system.
  474. XOn these systems, eftest will fail with a bus error until you modify the
  475. XMakefile to define
  476. X.B PAGE_PROTECTION_VIOLATED_SIGNAL
  477. Xas
  478. X.B SIGBUS.
  479. X.LP
  480. XThere are, without doubt, other bugs and porting issues. Please contact me via
  481. Xe-mail if you have any bug reports, ideas, etc.
  482. X.SH WHAT'S BETTER
  483. XPURIFY, from Purify Systems, does a much better job than Electric Fence, and
  484. Xdoes much more. It's available at this writing on SPARC systems only, soon
  485. Xon HP. I'm not affiliated with Purify, I just think it's a wonderful product
  486. Xand you should check it out.
  487. END_OF_FILE
  488. if test 14508 -ne `wc -c <'libefence.3'`; then
  489.     echo shar: \"'libefence.3'\" unpacked with wrong size!
  490. fi
  491. # end of 'libefence.3'
  492. fi
  493. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  494.   echo shar: Will not clobber existing file \"'Makefile'\"
  495. else
  496. echo shar: Extracting \"'Makefile'\" \(2008 characters\)
  497. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  498. XCC= cc
  499. XAR= ar
  500. XCP= cp
  501. XMV= mv
  502. XCHMOD= chmod
  503. XCFLAGS= -g
  504. XLIB_INSTALL_DIR= /usr/local/lib
  505. XMAN_INSTALL_DIR= /usr/local/man/man3
  506. X
  507. XPACKAGE_SOURCE= README libefence.3 Makefile efence.h \
  508. X    efence.c page.c print.c eftest.c tstheap.c
  509. X
  510. X# Un-comment the following if you are running HP/UX.
  511. X# CFLAGS= -Aa -g -D_HPUX_SOURCE -DPAGE_PROTECTION_VIOLATED_SIGNAL=SIGBUS
  512. X
  513. X# Un-comment the following if you are running AIX. This makes sure you won't
  514. X# get the shared-library malloc() rather than the Electric Fence malloc().
  515. X# COMPILE THE PROGRAMS YOU ARE DEBUGGING WITH THESE FLAGS, TOO.
  516. X# CFLAGS= -g -bnso -bnodelcsect -bI:/lib/syscalls.exp
  517. X
  518. X# Un-comment the following if you are running SunOS 4.X
  519. X# Note the definition of PAGE_PROTECTION_VIOLATED_SIGNAL. This may vary
  520. X# depend on what version of Sun hardware you have.
  521. X# You'll probably have to link the program you are debugging with -Bstatic,
  522. X# as well.
  523. X# CFLAGS= -g -Bstatic -DPAGE_PROTECTION_VIOLATED_SIGNAL=SIGBUS
  524. X
  525. XOBJECTS= efence.o page.o print.o
  526. X
  527. Xall:    libefence.a tstheap eftest
  528. X    @ echo
  529. X    @ echo "Testing Electric Fence."
  530. X    @ echo "After the last test, it should print that the test has PASSED."
  531. X    ./eftest
  532. X    ./tstheap 3072
  533. X    @ echo
  534. X    @ echo "Electric Fence confidence test PASSED." 
  535. X    @ echo
  536. X
  537. Xinstall: libefence.a libefence.3
  538. X    $(MV) libefence.a $(LIB_INSTALL_DIR)
  539. X    $(CHMOD) 644 $(LIB_INSTALL_DIR)/libefence.a
  540. X    $(CP) libefence.3 $(MAN_INSTALL_DIR)
  541. X    $(CHMOD) 644 $(MAN_INSTALL_DIR)/libefence.3
  542. X
  543. Xclean:
  544. X    - rm -f $(OBJECTS) tstheap.o eftest.o tstheap eftest libefence.a \
  545. X     libefence.cat ElectricFence.shar
  546. X
  547. Xroff:
  548. X    nroff -man < libefence.3 > libefence.cat
  549. X
  550. X
  551. XElectricFence.shar: $(PACKAGE_SOURCE)
  552. X    shar $(PACKAGE_SOURCE) > ElectricFence.shar
  553. X
  554. Xshar: ElectricFence.shar
  555. X
  556. Xlibefence.a: $(OBJECTS)
  557. X    - rm -f libefence.a
  558. X    $(AR) crv libefence.a $(OBJECTS)
  559. X
  560. Xtstheap: libefence.a tstheap.o
  561. X    - rm -f tstheap
  562. X    $(CC) $(CFLAGS) tstheap.o libefence.a -o tstheap
  563. X
  564. Xeftest: libefence.a eftest.o
  565. X    - rm -f eftest
  566. X    $(CC) $(CFLAGS) eftest.o libefence.a -o eftest
  567. X
  568. X$(OBJECTS) tstheap.o eftest.o: efence.h
  569. END_OF_FILE
  570. if test 2008 -ne `wc -c <'Makefile'`; then
  571.     echo shar: \"'Makefile'\" unpacked with wrong size!
  572. fi
  573. # end of 'Makefile'
  574. fi
  575. if test -f 'efence.h' -a "${1}" != "-c" ; then 
  576.   echo shar: Will not clobber existing file \"'efence.h'\"
  577. else
  578. echo shar: Extracting \"'efence.h'\" \(541 characters\)
  579. sed "s/^X//" >'efence.h' <<'END_OF_FILE'
  580. X#include <sys/types.h>
  581. X
  582. X/*
  583. X * This is used to declare functions with "C" linkage if we are compiling
  584. X * with C++ .
  585. X */
  586. X#ifdef    __cplusplus
  587. X#define    C_LINKAGE    "C"
  588. X#else
  589. X#define    C_LINKAGE
  590. X#endif
  591. X
  592. Xvoid            Page_AllowAccess(void * address, size_t size);
  593. Xvoid *            Page_Create(size_t size);
  594. Xvoid            Page_Delete(void * address, size_t size);
  595. Xvoid            Page_DenyAccess(void * address, size_t size);
  596. Xsize_t            Page_Size(void);
  597. X
  598. Xvoid            EF_Abort(const char * message, ...);
  599. Xvoid            EF_Exit(const char * message, ...);
  600. Xvoid            EF_Print(const char * message, ...);
  601. END_OF_FILE
  602. if test 541 -ne `wc -c <'efence.h'`; then
  603.     echo shar: \"'efence.h'\" unpacked with wrong size!
  604. fi
  605. # end of 'efence.h'
  606. fi
  607. if test -f 'efence.c' -a "${1}" != "-c" ; then 
  608.   echo shar: Will not clobber existing file \"'efence.c'\"
  609. else
  610. echo shar: Extracting \"'efence.c'\" \(22481 characters\)
  611. sed "s/^X//" >'efence.c' <<'END_OF_FILE'
  612. X/*
  613. X * Electric Fence - Red-Zone memory allocator.
  614. X * Bruce Perens, 1988, 1993
  615. X * 
  616. X * This is a special version of malloc() and company for debugging software
  617. X * that is suspected of overrunning or underrunning the boundaries of a
  618. X * malloc buffer, or touching free memory.
  619. X *
  620. X * It arranges for each malloc buffer to be followed (or preceded)
  621. X * in the address space by an inaccessable virtual memory page,
  622. X * and for free memory to be inaccessable. If software touches the
  623. X * inaccessable page, it will get an immediate segmentation
  624. X * fault. It is then trivial to uncover the offending code using a debugger.
  625. X *
  626. X * An advantage of this product over most malloc debuggers is that this one
  627. X * detects reading out of bounds as well as writing, and this one stops on
  628. X * the exact instruction that causes the error, rather than waiting until the
  629. X * next boundary check.
  630. X *
  631. X * There is one product that debugs malloc buffer overruns
  632. X * better than Electric Fence: "Purify" from Purify Systems, and that's only
  633. X * a small part of what Purify does. I'm not affiliated with Purify, I just
  634. X * respect a job well done.
  635. X *
  636. X * This version of malloc() should not be linked into production software,
  637. X * since it tremendously increases the time and memory overhead of malloc().
  638. X * Each malloc buffer will consume a minimum of two virtual memory pages,
  639. X * this is 16 kilobytes on many systems. On some systems it will be necessary
  640. X * to increase the amount of swap space in order to debug large programs that
  641. X * perform lots of allocation, because of the per-buffer overhead.
  642. X */
  643. X#include "efence.h"
  644. X#include <stdlib.h>
  645. X#include <unistd.h>
  646. X#include <memory.h>
  647. X#include <string.h>
  648. X
  649. Xstatic const char    version[] = "\n  Electric Fence 2.0.1"
  650. X " Copyright (C) 1987-1993 Bruce Perens.\n";
  651. X
  652. X/*
  653. X * MEMORY_CREATION_SIZE is the amount of memory to get from the operating
  654. X * system at one time. We'll break that memory down into smaller pieces for
  655. X * malloc buffers. One megabyte is probably a good value.
  656. X */
  657. X#define            MEMORY_CREATION_SIZE    1024 * 1024
  658. X
  659. X/*
  660. X * Enum Mode indicates the status of a malloc buffer.
  661. X */
  662. Xenum _Mode {
  663. X    NOT_IN_USE = 0,    /* Available to represent a malloc buffer. */
  664. X    FREE,        /* A free buffer. */
  665. X    ALLOCATED,    /* A buffer that is in use. */
  666. X    PROTECTED,    /* A freed buffer that can not be allocated again. */
  667. X    INTERNAL_USE    /* A buffer used internally by malloc(). */
  668. X};
  669. Xtypedef enum _Mode    Mode;
  670. X
  671. X/*
  672. X * Struct Slot contains all of the information about a malloc buffer except
  673. X * for the contents of its memory.
  674. X */
  675. Xstruct _Slot {
  676. X    void *        userAddress;
  677. X    void *        internalAddress;
  678. X    size_t        userSize;
  679. X    size_t        internalSize;
  680. X    Mode        mode;
  681. X};
  682. Xtypedef struct _Slot    Slot;
  683. X
  684. X/*
  685. X * EF_ALIGNMENT is a global variable used to control the default alignment
  686. X * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
  687. X * so that its name matches the name of the environment variable that is used
  688. X * to set it. This gives the programmer one less name to remember.
  689. X * If the value is -1, it will be set from the environment or sizeof(int)
  690. X * at run time.
  691. X */
  692. Xint        EF_ALIGNMENT = -1;
  693. X
  694. X/*
  695. X * EF_PROTECT_FREE is a global variable used to control the disposition of
  696. X * memory that is released using free(). It is all-caps so that its name
  697. X * matches the name of the environment variable that is used to set it.
  698. X * If its value is greater non-zero, memory released by free is made
  699. X * inaccessable and never allocated again. Any software that touches free
  700. X * memory will then get a segmentation fault. If its value is zero, freed
  701. X * memory will be available for reallocation, but will still be inaccessable
  702. X * until it is reallocated.
  703. X * If the value is -1, it will be set from the environment or to 0 at run-time.
  704. X */
  705. Xint        EF_PROTECT_FREE = -1;
  706. X
  707. X/*
  708. X * EF_PROTECT_BELOW is used to modify the behavior of the allocator. When
  709. X * its value is non-zero, the allocator will place an inaccessable page
  710. X * immediately _before_ the malloc buffer in the address space, instead
  711. X * of _after_ it. Use this to detect malloc buffer under-runs, rather than
  712. X * over-runs. It won't detect both at the same time, so you should test your
  713. X * software twice, once with this value clear, and once with it set.
  714. X * If the value is -1, it will be set from the environment or to zero at
  715. X * run-time
  716. X */
  717. Xint        EF_PROTECT_BELOW = -1;
  718. X
  719. X/*
  720. X * EF_ALLOW_MALLOC_0 is set if Electric Fence is to allow malloc(0). I
  721. X * trap malloc(0) by default because it is a common source of bugs.
  722. X */
  723. Xint        EF_ALLOW_MALLOC_0 = -1;
  724. X
  725. X/*
  726. X * allocationList points to the array of slot structures used to manage the
  727. X * malloc arena.
  728. X */
  729. Xstatic Slot *        allocationList = 0;
  730. X
  731. X/*
  732. X * allocationListSize is the size of the allocation list. This will always
  733. X * be a multiple of the page size.
  734. X */
  735. Xstatic size_t        allocationListSize = 0;
  736. X
  737. X/*
  738. X * slotCount is the number of Slot structures in allocationList.
  739. X */
  740. Xstatic size_t        slotCount = 0;
  741. X
  742. X/*
  743. X * unUsedSlots is the number of Slot structures that are currently available
  744. X * to represent new malloc buffers. When this number gets too low, we will
  745. X * create new slots.
  746. X */
  747. Xstatic size_t        unUsedSlots = 0;
  748. X
  749. X/*
  750. X * slotsPerPage is the number of slot structures that fit in a virtual
  751. X * memory page.
  752. X */
  753. Xstatic size_t        slotsPerPage = 0;
  754. X
  755. X/*
  756. X * internalUse is set when allocating and freeing the allocatior-internal
  757. X * data structures.
  758. X */
  759. Xstatic int        internalUse = 0;
  760. X
  761. X/*
  762. X * noAllocationListProtection is set to tell malloc() and free() not to
  763. X * manipulate the protection of the allocation list. This is only set in
  764. X * realloc(), which does it to save on slow system calls, and in
  765. X * allocateMoreSlots(), which does it because it changes the allocation list.
  766. X */
  767. Xstatic int        noAllocationListProtection = 0;
  768. X
  769. X/*
  770. X * bytesPerPage is set at run-time to the number of bytes per virtual-memory
  771. X * page, as returned by Page_Size().
  772. X */
  773. Xstatic size_t        bytesPerPage = 0;
  774. X
  775. X/*
  776. X * internalError is called for those "shouldn't happen" errors in the
  777. X * allocator.
  778. X */
  779. Xstatic void
  780. XinternalError(void)
  781. X{
  782. X    EF_Abort("Internal error in allocator.");
  783. X}
  784. X
  785. X/*
  786. X * initialize sets up the memory allocation arena and the run-time
  787. X * configuration information.
  788. X */
  789. Xstatic void
  790. Xinitialize(void)
  791. X{
  792. X    size_t    size = MEMORY_CREATION_SIZE;
  793. X    size_t    slack;
  794. X    char *    string;
  795. X    Slot *    slot;
  796. X
  797. X    EF_Print(version);
  798. X
  799. X    /*
  800. X     * Import the user's environment specification of the default
  801. X     * alignment for malloc(). We want that alignment to be under
  802. X     * user control, since smaller alignment lets us catch more bugs,
  803. X     * however some software will break if malloc() returns a buffer
  804. X     * that is not word-aligned.
  805. X     *
  806. X     * I would like
  807. X     * alignment to be zero so that we could catch all one-byte
  808. X     * overruns, however if malloc() is asked to allocate an odd-size
  809. X     * buffer and returns an address that is not word-aligned, or whose
  810. X     * size is not a multiple of the word size, software breaks.
  811. X     * This was the case with the Sun string-handling routines,
  812. X     * which can do word fetches up to three bytes beyond the end of a
  813. X     * string. I handle this problem in part by providing
  814. X     * byte-reference-only versions of the string library functions, but
  815. X     * there are other functions that break, too. Some in X Windows, one
  816. X     * in Sam Leffler's TIFF library, and doubtless many others.
  817. X     */
  818. X    if ( EF_ALIGNMENT == -1 ) {
  819. X        if ( (string = getenv("EF_ALIGNMENT")) != 0 )
  820. X            EF_ALIGNMENT = (size_t)atoi(string);
  821. X        else
  822. X            EF_ALIGNMENT = sizeof(int);
  823. X    }
  824. X
  825. X    /*
  826. X     * See if the user wants to protect the address space below a buffer,
  827. X     * rather than that above a buffer.
  828. X     */
  829. X    if ( EF_PROTECT_BELOW == -1 ) {
  830. X        if ( (string = getenv("EF_PROTECT_BELOW")) != 0 )
  831. X            EF_PROTECT_BELOW = (atoi(string) != 0);
  832. X        else
  833. X            EF_PROTECT_BELOW = 0;
  834. X    }
  835. X
  836. X    /*
  837. X     * See if the user wants to protect memory that has been freed until
  838. X     * the program exits, rather than until it is re-allocated.
  839. X     */
  840. X    if ( EF_PROTECT_FREE == -1 ) {
  841. X        if ( (string = getenv("EF_PROTECT_FREE")) != 0 )
  842. X            EF_PROTECT_FREE = (atoi(string) != 0);
  843. X        else
  844. X            EF_PROTECT_FREE = 0;
  845. X    }
  846. X
  847. X    /*
  848. X     * See if the user wants to allow malloc(0).
  849. X     */
  850. X    if ( EF_ALLOW_MALLOC_0 == -1 ) {
  851. X        if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )
  852. X            EF_ALLOW_MALLOC_0 = (atoi(string) != 0);
  853. X        else
  854. X            EF_ALLOW_MALLOC_0 = 0;
  855. X    }
  856. X
  857. X    /*
  858. X     * Get the run-time configuration of the virtual memory page size.
  859. X      */
  860. X    bytesPerPage = Page_Size();
  861. X
  862. X    /*
  863. X     * Figure out how many Slot structures to allocate at one time.
  864. X     */
  865. X    slotCount = slotsPerPage = bytesPerPage / sizeof(Slot);
  866. X    allocationListSize = bytesPerPage;
  867. X
  868. X    if ( allocationListSize > size )
  869. X        size = allocationListSize;
  870. X
  871. X    if ( (slack = size % bytesPerPage) != 0 )
  872. X        size += bytesPerPage - slack;
  873. X
  874. X    /*
  875. X     * Allocate memory, and break it up into two malloc buffers. The
  876. X     * first buffer will be used for Slot structures, the second will
  877. X     * be marked free.
  878. X     */
  879. X    slot = allocationList = (Slot *)Page_Create(size);
  880. X    memset((char *)allocationList, 0, allocationListSize);
  881. X
  882. X    slot[0].internalSize = slot[0].userSize = allocationListSize;
  883. X    slot[0].internalAddress = slot[0].userAddress = allocationList;
  884. X    slot[0].mode = INTERNAL_USE;
  885. X    if ( size > allocationListSize ) {
  886. X        slot[1].internalAddress = slot[1].userAddress
  887. X         = ((char *)slot[0].internalAddress) + slot[0].internalSize;
  888. X        slot[1].internalSize
  889. X         = slot[1].userSize = size - slot[0].internalSize;
  890. X        slot[1].mode = FREE;
  891. X    }
  892. X
  893. X    /*
  894. X     * Deny access to the free page, so that we will detect any software
  895. X     * that treads upon free memory.
  896. X     */
  897. X    Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
  898. X
  899. X    /*
  900. X     * Account for the two slot structures that we've used.
  901. X     */
  902. X    unUsedSlots = slotCount - 2;
  903. X}
  904. X
  905. X/*
  906. X * allocateMoreSlots is called when there are only enough slot structures
  907. X * left to support the allocation of a single malloc buffer.
  908. X */
  909. Xstatic void
  910. XallocateMoreSlots(void)
  911. X{
  912. X    size_t    newSize = allocationListSize + bytesPerPage;
  913. X    void *    newAllocation;
  914. X    void *    oldAllocation = allocationList;
  915. X
  916. X    Page_AllowAccess(allocationList, allocationListSize);
  917. X    noAllocationListProtection = 1;
  918. X    internalUse = 1;
  919. X
  920. X    newAllocation = malloc(newSize);
  921. X    memcpy(newAllocation, allocationList, allocationListSize);
  922. X    memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage);
  923. X
  924. X    allocationList = (Slot *)newAllocation;
  925. X    allocationListSize = newSize;
  926. X    slotCount += slotsPerPage;
  927. X    unUsedSlots += slotsPerPage;
  928. X
  929. X    free(oldAllocation);
  930. X
  931. X    /*
  932. X     * Keep access to the allocation list open at this point, because
  933. X     * I am returning to memalign(), which needs that access.
  934. X      */
  935. X    noAllocationListProtection = 0;
  936. X    internalUse = 0;
  937. X}
  938. X
  939. X/*
  940. X * This is the memory allocator. When asked to allocate a buffer, allocate
  941. X * it in such a way that the end of the buffer is followed by an inaccessable
  942. X * memory page. If software overruns that buffer, it will touch the bad page
  943. X * and get an immediate segmentation fault. It's then easy to zero in on the
  944. X * offending code with a debugger.
  945. X *
  946. X * There are a few complications. If the user asks for an odd-sized buffer,
  947. X * we would have to have that buffer start on an odd address if the byte after
  948. X * the end of the buffer was to be on the inaccessable page. Unfortunately,
  949. X * there is lots of software that asks for odd-sized buffers and then
  950. X * requires that the returned address be word-aligned, or the size of the
  951. X * buffer be a multiple of the word size. An example are the string-processing
  952. X * functions on Sun systems, which do word references to the string memory
  953. X * and may refer to memory up to three bytes beyond the end of the string.
  954. X * For this reason, I take the alignment requests to memalign() and valloc()
  955. X * seriously, and 
  956. X * 
  957. X * Electric Fence wastes lots of memory. I do a best-fit allocator here
  958. X * so that it won't waste even more. It's slow, but thrashing because your
  959. X * working set is too big for a system's RAM is even slower. 
  960. X */
  961. Xextern C_LINKAGE void *
  962. Xmemalign(size_t alignment, size_t userSize)
  963. X{
  964. X    register Slot *    slot;
  965. X    register size_t    count;
  966. X    Slot *        fullSlot = 0;
  967. X    Slot *        emptySlots[2];
  968. X    size_t        internalSize;
  969. X    size_t        slack;
  970. X    char *        address;
  971. X
  972. X
  973. X    if ( allocationList == 0 )
  974. X        initialize();
  975. X
  976. X    if ( userSize == 0 && !EF_ALLOW_MALLOC_0 )
  977. X        EF_Abort("Allocating 0 bytes, probably a bug.");
  978. X
  979. X    /*
  980. X     * If EF_PROTECT_BELOW is set, all addresses returned by malloc()
  981. X     * and company will be page-aligned.
  982. X      */
  983. X    if ( !EF_PROTECT_BELOW && alignment > 1 ) {
  984. X        if ( (slack = userSize % alignment) != 0 )
  985. X            userSize += alignment - slack;
  986. X    }
  987. X
  988. X    /*
  989. X     * The internal size of the buffer is rounded up to the next page-size
  990. X     * boudary, and then we add another page's worth of memory for the
  991. X     * dead page.
  992. X     */
  993. X    internalSize = userSize + bytesPerPage;
  994. X    if ( (slack = internalSize % bytesPerPage) != 0 )
  995. X        internalSize += bytesPerPage - slack;
  996. X
  997. X    /*
  998. X     * These will hold the addresses of two empty Slot structures, that
  999. X     * can be used to hold information for any memory I create, and any
  1000. X     * memory that I mark free.
  1001. X     */
  1002. X    emptySlots[0] = 0;
  1003. X    emptySlots[1] = 0;
  1004. X
  1005. X    /*
  1006. X     * The internal memory used by the allocator is currently
  1007. X     * inaccessable, so that errant programs won't scrawl on the
  1008. X     * allocator's arena. I'll un-protect it here so that I can make
  1009. X     * a new allocation. I'll re-protect it before I return.
  1010. X      */
  1011. X    if ( !noAllocationListProtection )
  1012. X        Page_AllowAccess(allocationList, allocationListSize);
  1013. X
  1014. X    /*
  1015. X     * If I'm running out of empty slots, create some more before
  1016. X     * I don't have enough slots left to make an allocation.
  1017. X     */
  1018. X    if ( !internalUse && unUsedSlots < 7 ) {
  1019. X        allocateMoreSlots();
  1020. X    }
  1021. X    
  1022. X    /*
  1023. X     * Iterate through all of the slot structures. Attempt to find a slot
  1024. X     * containing free memory of the exact right size. Accept a slot with
  1025. X     * more memory than we want, if the exact right size is not available.
  1026. X     * Find two slot structures that are not in use. We will need one if
  1027. X     * we split a buffer into free and allocated parts, and the second if
  1028. X     * we have to create new memory and mark it as free.
  1029. X     *
  1030. X     */
  1031. X    
  1032. X    for ( slot = allocationList, count = slotCount ; count > 0; count-- ) {
  1033. X        if ( slot->mode == FREE
  1034. X         && slot->internalSize >= internalSize ) {
  1035. X            if ( !fullSlot
  1036. X             ||slot->internalSize < fullSlot->internalSize){
  1037. X                fullSlot = slot;
  1038. X                if ( slot->internalSize == internalSize
  1039. X                 && emptySlots[0] )
  1040. X                    break;    /* All done, */
  1041. X            }
  1042. X        }
  1043. X        else if ( slot->mode == NOT_IN_USE ) {
  1044. X            if ( !emptySlots[0] )
  1045. X                emptySlots[0] = slot;
  1046. X            else if ( !emptySlots[1] )
  1047. X                emptySlots[1] = slot;
  1048. X            else if ( fullSlot
  1049. X             && fullSlot->internalSize == internalSize )
  1050. X                break;    /* All done. */
  1051. X        }
  1052. X        slot++;
  1053. X    }
  1054. X    if ( !emptySlots[0] )
  1055. X        internalError();
  1056. X
  1057. X    if ( !fullSlot ) {
  1058. X        /*
  1059. X         * I get here if I haven't been able to find a free buffer
  1060. X         * with all of the memory I need. I'll have to create more
  1061. X         * memory. I'll mark it all as free, and then split it into
  1062. X         * free and allocated portions later.
  1063. X         */
  1064. X        size_t    chunkSize = MEMORY_CREATION_SIZE;
  1065. X
  1066. X        if ( !emptySlots[1] )
  1067. X            internalError();
  1068. X
  1069. X        if ( chunkSize < internalSize )
  1070. X            chunkSize = internalSize;
  1071. X
  1072. X        if ( (slack = chunkSize % bytesPerPage) != 0 )
  1073. X            chunkSize += bytesPerPage - slack;
  1074. X
  1075. X        /* Use up one of the empty slots to make the full slot. */
  1076. X        fullSlot = emptySlots[0];
  1077. X        emptySlots[0] = emptySlots[1];
  1078. X        fullSlot->internalAddress = Page_Create(chunkSize);
  1079. X        fullSlot->internalSize = chunkSize;
  1080. X        fullSlot->mode = FREE;
  1081. X        unUsedSlots--;
  1082. X    }
  1083. X
  1084. X    /*
  1085. X     * If I'm allocating memory for the allocator's own data structures,
  1086. X     * mark it INTERNAL_USE so that no errant software will be able to
  1087. X     * free it.
  1088. X     */
  1089. X    if ( internalUse )
  1090. X        fullSlot->mode = INTERNAL_USE;
  1091. X    else
  1092. X        fullSlot->mode = ALLOCATED;
  1093. X
  1094. X    /*
  1095. X     * If the buffer I've found is larger than I need, split it into
  1096. X     * an allocated buffer with the exact amount of memory I need, and
  1097. X     * a free buffer containing the surplus memory.
  1098. X     */
  1099. X    if ( fullSlot->internalSize > internalSize ) {
  1100. X        emptySlots[0]->internalSize
  1101. X         = fullSlot->internalSize - internalSize;
  1102. X        emptySlots[0]->internalAddress
  1103. X         = ((char *)fullSlot->internalAddress) + internalSize;
  1104. X        emptySlots[0]->mode = FREE;
  1105. X        fullSlot->internalSize = internalSize;
  1106. X        unUsedSlots--;
  1107. X    }
  1108. X
  1109. X    if ( !EF_PROTECT_BELOW ) {
  1110. X        /*
  1111. X         * Arrange the buffer so that it is followed by an inaccessable
  1112. X         * memory page. A buffer overrun that touches that page will
  1113. X         * cause a segmentation fault.
  1114. X         */
  1115. X        address = (char *)fullSlot->internalAddress;
  1116. X
  1117. X        /* Set up the "live" page. */
  1118. X        Page_AllowAccess(
  1119. X         fullSlot->internalAddress
  1120. X        ,internalSize - bytesPerPage);
  1121. X            
  1122. X        address += internalSize - bytesPerPage;
  1123. X
  1124. X        /* Set up the "dead" page. */
  1125. X        if ( EF_PROTECT_FREE )
  1126. X            Page_Delete(address, bytesPerPage);
  1127. X        else
  1128. X            Page_DenyAccess(address, bytesPerPage);
  1129. X
  1130. X        /* Figure out what address to give the user. */
  1131. X        address -= userSize;
  1132. X    }
  1133. X    else {    /* EF_PROTECT_BELOW != 0 */
  1134. X        /*
  1135. X         * Arrange the buffer so that it is preceded by an inaccessable
  1136. X         * memory page. A buffer underrun that touches that page will
  1137. X         * cause a segmentation fault.
  1138. X         */
  1139. X        address = (char *)fullSlot->internalAddress;
  1140. X
  1141. X        /* Set up the "dead" page. */
  1142. X        if ( EF_PROTECT_FREE )
  1143. X            Page_Delete(address, bytesPerPage);
  1144. X        else
  1145. X            Page_DenyAccess(address, bytesPerPage);
  1146. X            
  1147. X        address += bytesPerPage;
  1148. X
  1149. X        /* Set up the "live" page. */
  1150. X        Page_AllowAccess(address, internalSize - bytesPerPage);
  1151. X    }
  1152. X
  1153. X    fullSlot->userAddress = address;
  1154. X    fullSlot->userSize = userSize;
  1155. X
  1156. X    /*
  1157. X     * Make the pool's internal memory inaccessable, so that the program
  1158. X     * being debugged can't stomp on it.
  1159. X     */
  1160. X    if ( !internalUse )
  1161. X        Page_DenyAccess(allocationList, allocationListSize);
  1162. X
  1163. X    return address;
  1164. X}
  1165. X
  1166. X/*
  1167. X * Find the slot structure for a user address.
  1168. X */
  1169. Xstatic Slot *
  1170. XslotForUserAddress(void * address)
  1171. X{
  1172. X    register Slot *    slot = allocationList;
  1173. X    register size_t    count = slotCount;
  1174. X    
  1175. X    for ( ; count > 0; count-- ) {
  1176. X        if ( slot->userAddress == address )
  1177. X            return slot;
  1178. X        slot++;
  1179. X    }
  1180. X
  1181. X    return 0;
  1182. X}
  1183. X
  1184. X/*
  1185. X * Find the slot structure for an internal address.
  1186. X */
  1187. Xstatic Slot *
  1188. XslotForInternalAddress(void * address)
  1189. X{
  1190. X    register Slot *    slot = allocationList;
  1191. X    register size_t    count = slotCount;
  1192. X    
  1193. X    for ( ; count > 0; count-- ) {
  1194. X        if ( slot->internalAddress == address )
  1195. X            return slot;
  1196. X        slot++;
  1197. X    }
  1198. X    return 0;
  1199. X}
  1200. X
  1201. X/*
  1202. X * Given the internal address of a buffer, find the buffer immediately
  1203. X * before that buffer in the address space. This is used by free() to
  1204. X * coalesce two free buffers into one.
  1205. X */
  1206. Xstatic Slot *
  1207. XslotForInternalAddressPreviousTo(void * address)
  1208. X{
  1209. X    register Slot *    slot = allocationList;
  1210. X    register size_t    count = slotCount;
  1211. X    
  1212. X    for ( ; count > 0; count-- ) {
  1213. X        if ( ((char *)slot->internalAddress)
  1214. X         + slot->internalSize == address )
  1215. X            return slot;
  1216. X        slot++;
  1217. X    }
  1218. X    return 0;
  1219. X}
  1220. X
  1221. Xextern C_LINKAGE void
  1222. Xfree(void * address)
  1223. X{
  1224. X    Slot *    slot;
  1225. X    Slot *    previousSlot = 0;
  1226. X    Slot *    nextSlot = 0;
  1227. X
  1228. X    if ( address == 0 )
  1229. X        EF_Abort("free() called for address zero.");
  1230. X
  1231. X    if ( allocationList == 0 )
  1232. X        EF_Abort("free() called before first malloc().");
  1233. X
  1234. X    if ( !noAllocationListProtection )
  1235. X        Page_AllowAccess(allocationList, allocationListSize);
  1236. X
  1237. X    slot = slotForUserAddress(address);
  1238. X
  1239. X    if ( !slot )
  1240. X        EF_Abort("free(%x): address not from malloc().", address);
  1241. X
  1242. X    if ( slot->mode != ALLOCATED ) {
  1243. X        if ( internalUse && slot->mode == INTERNAL_USE )
  1244. X            /* Do nothing. */;
  1245. X        else {
  1246. X            EF_Abort(
  1247. X             "free(%x): freeing free memory."
  1248. X            ,address);
  1249. X        }
  1250. X    }
  1251. X
  1252. X    if ( EF_PROTECT_FREE )
  1253. X        slot->mode = PROTECTED;
  1254. X    else
  1255. X        slot->mode = FREE;
  1256. X
  1257. X    previousSlot = slotForInternalAddressPreviousTo(slot->internalAddress);
  1258. X    nextSlot = slotForInternalAddress(
  1259. X     ((char *)slot->internalAddress) + slot->internalSize);
  1260. X
  1261. X    if ( previousSlot
  1262. X     && (previousSlot->mode == FREE || previousSlot->mode == PROTECTED) ) {
  1263. X        /* Coalesce previous slot with this one. */
  1264. X        previousSlot->internalSize += slot->internalSize;
  1265. X        if ( EF_PROTECT_FREE )
  1266. X            previousSlot->mode = PROTECTED;
  1267. X
  1268. X        slot->internalAddress = slot->userAddress = 0;
  1269. X        slot->internalSize = slot->userSize = 0;
  1270. X        slot->mode = NOT_IN_USE;
  1271. X        slot = previousSlot;
  1272. X        unUsedSlots++;
  1273. X    }
  1274. X    if ( nextSlot
  1275. X     && (nextSlot->mode == FREE || nextSlot->mode == PROTECTED) ) {
  1276. X        /* Coalesce next slot with this one. */
  1277. X        slot->internalSize += nextSlot->internalSize;
  1278. X        nextSlot->internalAddress = nextSlot->userAddress = 0;
  1279. X        nextSlot->internalSize = nextSlot->userSize = 0;
  1280. X        nextSlot->mode = NOT_IN_USE;
  1281. X        unUsedSlots++;
  1282. X    }
  1283. X
  1284. X    slot->userAddress = slot->internalAddress;
  1285. X    slot->userSize = slot->internalSize;
  1286. X
  1287. X    /*
  1288. X     * Free memory is _always_ set to deny access. When EF_PROTECT_FREE
  1289. X     * is true, free memory is never reallocated, so it remains access
  1290. X     * denied for the life of the process. When EF_PROTECT_FREE is false, 
  1291. X     * the memory may be re-allocated, at which time access to it will be
  1292. X     * allowed again.
  1293. X     *
  1294. X     * Some operating systems allow munmap() with single-page resolution,
  1295. X     * and allow you to un-map portions of a region, rather than the
  1296. X     * entire region that was mapped with mmap(). On those operating
  1297. X     * systems, we can release protected free pages with Page_Delete(),
  1298. X     * in the hope that the swap space attached to those pages will be
  1299. X     * released as well.
  1300. X     */
  1301. X    if ( EF_PROTECT_FREE )
  1302. X        Page_Delete(slot->internalAddress, slot->internalSize);
  1303. X    else
  1304. X        Page_DenyAccess(slot->internalAddress, slot->internalSize);
  1305. X
  1306. X    if ( !noAllocationListProtection )
  1307. X        Page_DenyAccess(allocationList, allocationListSize);
  1308. X}
  1309. X
  1310. Xextern C_LINKAGE void *
  1311. Xrealloc(void * oldBuffer, size_t newSize)
  1312. X{
  1313. X    size_t    size;
  1314. X    Slot *    slot;
  1315. X    void *    newBuffer = malloc(newSize);
  1316. X
  1317. X    if ( allocationList == 0 )
  1318. X        EF_Abort("realloc() called before first malloc().");
  1319. X
  1320. X    Page_AllowAccess(allocationList, allocationListSize);
  1321. X    noAllocationListProtection = 1;
  1322. X    
  1323. X    slot = slotForUserAddress(oldBuffer);
  1324. X
  1325. X    if ( slot == 0 )
  1326. X        EF_Abort("free(%x): not from malloc().", oldBuffer);
  1327. X
  1328. X    if ( newSize < (size = slot->userSize) )
  1329. X        size = newSize;
  1330. X
  1331. X    if ( size > 0 )
  1332. X        memcpy(newBuffer, oldBuffer, size);
  1333. X
  1334. X    free(oldBuffer);
  1335. X    noAllocationListProtection = 0;
  1336. X    Page_DenyAccess(allocationList, allocationListSize);
  1337. X
  1338. X    if ( size < newSize )
  1339. X        memset(&(((char *)newBuffer)[size]), 0, newSize - size);
  1340. X    
  1341. X    /* Internal memory was re-protected in free() */
  1342. X    return newBuffer;
  1343. X}
  1344. X
  1345. Xextern C_LINKAGE void *
  1346. Xmalloc(size_t size)
  1347. X{
  1348. X    if ( allocationList == 0 )
  1349. X        initialize();    /* This sets EF_ALIGNMENT */
  1350. X
  1351. X    return memalign(EF_ALIGNMENT, size);
  1352. X}
  1353. X
  1354. Xextern C_LINKAGE void *
  1355. Xcalloc(size_t nelem, size_t elsize)
  1356. X{
  1357. X    size_t    size = nelem * elsize;
  1358. X    void *    allocation = malloc(size);
  1359. X
  1360. X    memset(allocation, 0, size);
  1361. X    return allocation;
  1362. X}
  1363. X
  1364. X/*
  1365. X * This will catch more bugs if you remove the page alignment, but it
  1366. X * will break some software.
  1367. X */
  1368. Xextern C_LINKAGE void *
  1369. Xvalloc (size_t size)
  1370. X{
  1371. X    return memalign(bytesPerPage, size);
  1372. X}
  1373. END_OF_FILE
  1374. if test 22481 -ne `wc -c <'efence.c'`; then
  1375.     echo shar: \"'efence.c'\" unpacked with wrong size!
  1376. fi
  1377. # end of 'efence.c'
  1378. fi
  1379. if test -f 'page.c' -a "${1}" != "-c" ; then 
  1380.   echo shar: Will not clobber existing file \"'page.c'\"
  1381. else
  1382. echo shar: Extracting \"'page.c'\" \(3678 characters\)
  1383. sed "s/^X//" >'page.c' <<'END_OF_FILE'
  1384. X#include "efence.h"
  1385. X#include <stdlib.h>
  1386. X#include <unistd.h>
  1387. X#include <fcntl.h>
  1388. X#include <sys/mman.h>
  1389. X#include <stdio.h>
  1390. X#include <errno.h>
  1391. X#include <string.h>
  1392. X
  1393. X/*
  1394. X * For some reason, I can't find mprotect() in any of the headers on
  1395. X * IRIX or SunOS 4.1.2
  1396. X */
  1397. Xextern C_LINKAGE int mprotect(caddr_t addr, size_t len, int prot);
  1398. X
  1399. Xstatic caddr_t    startAddr = (caddr_t) 0;
  1400. X
  1401. X#if ( !defined(sgi) && !defined(_AIX) )
  1402. Xextern int    sys_nerr;
  1403. Xextern char *    sys_errlist[];
  1404. X#endif
  1405. X
  1406. Xstatic const char *
  1407. XstringErrorReport(void)
  1408. X{
  1409. X#if ( defined(sgi) )
  1410. X    return strerror(oserror());
  1411. X#elif ( defined(_AIX) )
  1412. X    return strerror(errno);
  1413. X#else
  1414. X    if ( errno > 0 && errno < sys_nerr )
  1415. X        return sys_errlist[errno];
  1416. X    else
  1417. X        return "Unknown error.\n";
  1418. X#endif
  1419. X}
  1420. X
  1421. X/*
  1422. X * Create memory.
  1423. X */
  1424. X#if defined(MAP_ANONYMOUS)
  1425. Xvoid *
  1426. XPage_Create(size_t size)
  1427. X{
  1428. X    caddr_t        allocation;
  1429. X
  1430. X    /*
  1431. X     * In this version, "startAddr" is a _hint_, not a demand.
  1432. X     * When the memory I map here is contiguous with other
  1433. X     * mappings, the allocator can coalesce the memory from two
  1434. X     * or more mappings into one large contiguous chunk, and thus
  1435. X     * might be able to find a fit that would not otherwise have
  1436. X     * been possible. I could _force_ it to be contiguous by using
  1437. X     * the MMAP_FIXED flag, but I don't want to stomp on memory mappings
  1438. X     * generated by other software, etc.
  1439. X     */
  1440. X    allocation = mmap(
  1441. X     startAddr
  1442. X    ,(int)size
  1443. X    ,PROT_READ|PROT_WRITE
  1444. X    ,MAP_PRIVATE|MAP_ANONYMOUS
  1445. X    ,-1
  1446. X    ,0);
  1447. X
  1448. X    startAddr = allocation + size;
  1449. X
  1450. X    if ( allocation == (caddr_t)-1 )
  1451. X        EF_Exit("mmap() failed: %s", stringErrorReport());
  1452. X
  1453. X    return (void *)allocation;
  1454. X}
  1455. X#else
  1456. Xvoid *
  1457. XPage_Create(size_t size)
  1458. X{
  1459. X    static int    devZeroFd = -1;
  1460. X    caddr_t        allocation;
  1461. X
  1462. X    if ( devZeroFd == -1 ) {
  1463. X        devZeroFd = open("/dev/zero", O_RDWR);
  1464. X        if ( devZeroFd < 0 )
  1465. X            EF_Exit(
  1466. X             "open() on /dev/zero failed: %s"
  1467. X            ,stringErrorReport());
  1468. X    }
  1469. X
  1470. X    /*
  1471. X     * In this version, "startAddr" is a _hint_, not a demand.
  1472. X     * When the memory I map here is contiguous with other
  1473. X     * mappings, the allocator can coalesce the memory from two
  1474. X     * or more mappings into one large contiguous chunk, and thus
  1475. X     * might be able to find a fit that would not otherwise have
  1476. X     * been possible. I could _force_ it to be contiguous by using
  1477. X     * the MMAP_FIXED flag, but I don't want to stomp on memory mappings
  1478. X     * generated by other software, etc.
  1479. X     */
  1480. X    allocation = mmap(
  1481. X     startAddr
  1482. X    ,(int)size
  1483. X    ,PROT_READ|PROT_WRITE
  1484. X    ,MAP_PRIVATE
  1485. X    ,devZeroFd
  1486. X    ,0);
  1487. X
  1488. X    startAddr = allocation + size;
  1489. X
  1490. X    if ( allocation == (caddr_t)-1 )
  1491. X        EF_Exit("mmap() failed: %s", stringErrorReport());
  1492. X
  1493. X    return (void *)allocation;
  1494. X}
  1495. X#endif
  1496. X
  1497. Xstatic void
  1498. XmprotectFailed(void)
  1499. X{
  1500. X    EF_Exit("mprotect() failed: %s", stringErrorReport());
  1501. X}
  1502. X
  1503. Xvoid
  1504. XPage_AllowAccess(void * address, size_t size)
  1505. X{
  1506. X    if ( mprotect((caddr_t)address, size, PROT_READ|PROT_WRITE) < 0 )
  1507. X        mprotectFailed();
  1508. X}
  1509. X
  1510. Xvoid
  1511. XPage_DenyAccess(void * address, size_t size)
  1512. X{
  1513. X    if ( mprotect((caddr_t)address, size, PROT_NONE) < 0 )
  1514. X        mprotectFailed();
  1515. X}
  1516. X
  1517. Xvoid
  1518. XPage_Delete(void * address, size_t size)
  1519. X{
  1520. X/*
  1521. X * My SGI ONYX running IRIX 5.0 crashes reliably when "tstheap 3072" is
  1522. X * run with the munmap call below compiled in. I'd like to hear how well
  1523. X * other operating systems handle it, so that I can enable it on those
  1524. X * systems.
  1525. X */
  1526. X#if ( defined(_AIX) )
  1527. X    if ( munmap((caddr_t)address, size) < 0 )
  1528. X        EF_Exit("munmap() failed: %s", stringErrorReport());
  1529. X#else
  1530. X    Page_DenyAccess(address, size);
  1531. X#endif
  1532. X}
  1533. X
  1534. X#if defined(_SC_PAGESIZE)
  1535. Xsize_t
  1536. XPage_Size(void)
  1537. X{
  1538. X    return (size_t)sysconf(_SC_PAGESIZE);
  1539. X}
  1540. X#elif defined(_SC_PAGE_SIZE)
  1541. Xsize_t
  1542. XPage_Size(void)
  1543. X{
  1544. X    return (size_t)sysconf(_SC_PAGE_SIZE);
  1545. X}
  1546. X#else
  1547. Xextern int    getpagesize();
  1548. Xsize_t
  1549. XPage_Size(void)
  1550. X{
  1551. X    return getpagesize();
  1552. X}
  1553. X#endif
  1554. END_OF_FILE
  1555. if test 3678 -ne `wc -c <'page.c'`; then
  1556.     echo shar: \"'page.c'\" unpacked with wrong size!
  1557. fi
  1558. # end of 'page.c'
  1559. fi
  1560. if test -f 'print.c' -a "${1}" != "-c" ; then 
  1561.   echo shar: Will not clobber existing file \"'print.c'\"
  1562. else
  1563. echo shar: Extracting \"'print.c'\" \(2956 characters\)
  1564. sed "s/^X//" >'print.c' <<'END_OF_FILE'
  1565. X#include "efence.h"
  1566. X#include <stdlib.h>
  1567. X#include <unistd.h>
  1568. X#include <stdarg.h>
  1569. X#include <string.h>
  1570. X#include <signal.h>
  1571. X
  1572. X/*
  1573. X * These routines do their printing without using stdio. Stdio can't
  1574. X * be used because it calls malloc(). Internal routines of a malloc()
  1575. X * debugger should not re-enter malloc(), so stdio is out.
  1576. X */
  1577. X
  1578. X/*
  1579. X * NUMBER_BUFFER_SIZE is the longest character string that could be needed
  1580. X * to represent an unsigned integer. Assuming unsigned integers might be as
  1581. X * large as 64 bits, and we might print in base 2, let's set it to 64 bytes.
  1582. X */
  1583. X#define    NUMBER_BUFFER_SIZE    64
  1584. X
  1585. Xstatic void
  1586. XprintNumber(unsigned int number, unsigned int base)
  1587. X{
  1588. X    char        buffer[NUMBER_BUFFER_SIZE];
  1589. X    char *        s = &buffer[NUMBER_BUFFER_SIZE];
  1590. X    int        size;
  1591. X    
  1592. X    do {
  1593. X        unsigned int    digit;
  1594. X
  1595. X        if ( --s == buffer )
  1596. X            EF_Abort("Internal error printing number.");
  1597. X
  1598. X        digit = number % base;
  1599. X
  1600. X        if ( digit < 10 )
  1601. X            *s = '0' + digit;
  1602. X        else
  1603. X            *s = 'a' + digit - 10;
  1604. X
  1605. X    } while ( (number /= base) > 0 );
  1606. X
  1607. X    size = &buffer[NUMBER_BUFFER_SIZE] - s;
  1608. X
  1609. X    if ( size > 0 )
  1610. X        write(2, s, size);
  1611. X}
  1612. X
  1613. Xstatic void
  1614. Xvprint(const char * pattern, va_list args)
  1615. X{
  1616. X    static const char    bad_pattern[] =
  1617. X     "\nBad pattern specifier %%%c in EF_Print().\n";
  1618. X    const char *    s = pattern;
  1619. X    char        c;
  1620. X
  1621. X    while ( (c = *s++) != '\0' ) {
  1622. X        if ( c == '%' ) {
  1623. X            c = *s++;
  1624. X            switch ( c ) {
  1625. X            case '%':
  1626. X                (void) write(2, &c, 1);
  1627. X                break;
  1628. X            case 's':
  1629. X                {
  1630. X                    const char *    string;
  1631. X                    size_t        length;
  1632. X
  1633. X                    string = va_arg(args, char *);
  1634. X                    length = strlen(string);
  1635. X
  1636. X                    (void) write(2, string, length);
  1637. X                }
  1638. X                break;
  1639. X            case 'd':
  1640. X                {
  1641. X                    int    n = va_arg(args, int);
  1642. X
  1643. X                    if ( n < 0 ) {
  1644. X                        char    c = '-';
  1645. X                        write(2, &c, 1);
  1646. X                        n = -n;
  1647. X                    }
  1648. X                    printNumber(n, 10);
  1649. X                }
  1650. X                break;
  1651. X            case 'x':
  1652. X                printNumber(va_arg(args, u_int), 0x10);
  1653. X                break;
  1654. X            case 'c':
  1655. X                {
  1656. X                    char    c = va_arg(args, char);
  1657. X                    
  1658. X                    (void) write(2, &c, 1);
  1659. X                }
  1660. X                break;
  1661. X            default:
  1662. X                {
  1663. X                    EF_Print(bad_pattern, c);
  1664. X                }
  1665. X        
  1666. X            }
  1667. X        }
  1668. X        else
  1669. X            (void) write(2, &c, 1);
  1670. X    }
  1671. X}
  1672. X
  1673. Xvoid
  1674. XEF_Abort(const char * pattern, ...)
  1675. X{
  1676. X    va_list    args;
  1677. X
  1678. X    va_start(args, pattern);
  1679. X
  1680. X    EF_Print("\nElectricFence Aborting: ");
  1681. X    vprint(pattern, args);
  1682. X    EF_Print("\n");
  1683. X
  1684. X    va_end(args);
  1685. X
  1686. X    /*
  1687. X     * I use kill(getpid(), SIGILL) instead of abort() because some
  1688. X     * mis-guided implementations of abort() flush stdio, which can
  1689. X     * cause malloc() or free() to be called.
  1690. X     */
  1691. X    kill(getpid(), SIGILL);
  1692. X    /* Just in case something handles SIGILL and returns, exit here. */
  1693. X    _exit(-1);
  1694. X}
  1695. X
  1696. Xvoid
  1697. XEF_Exit(const char * pattern, ...)
  1698. X{
  1699. X    va_list    args;
  1700. X
  1701. X    va_start(args, pattern);
  1702. X
  1703. X    EF_Print("\nElectricFence Exiting: ");
  1704. X    vprint(pattern, args);
  1705. X    EF_Print("\n");
  1706. X
  1707. X    va_end(args);
  1708. X
  1709. X    /*
  1710. X     * I use _exit() because the regular exit() flushes stdio,
  1711. X     * which may cause malloc() or free() to be called.
  1712. X     */
  1713. X    _exit(-1);
  1714. X}
  1715. X
  1716. Xvoid
  1717. XEF_Print(const char * pattern, ...)
  1718. X{
  1719. X    va_list    args;
  1720. X
  1721. X    va_start(args, pattern);
  1722. X    vprint(pattern, args);
  1723. X    va_end(args);
  1724. X}
  1725. END_OF_FILE
  1726. if test 2956 -ne `wc -c <'print.c'`; then
  1727.     echo shar: \"'print.c'\" unpacked with wrong size!
  1728. fi
  1729. # end of 'print.c'
  1730. fi
  1731. if test -f 'eftest.c' -a "${1}" != "-c" ; then 
  1732.   echo shar: Will not clobber existing file \"'eftest.c'\"
  1733. else
  1734. echo shar: Extracting \"'eftest.c'\" \(3490 characters\)
  1735. sed "s/^X//" >'eftest.c' <<'END_OF_FILE'
  1736. X#include <stdlib.h>
  1737. X#include <stdio.h>
  1738. X#include <string.h>
  1739. X#include <unistd.h>
  1740. X#include <setjmp.h>
  1741. X#include <signal.h>
  1742. X#include "efence.h"
  1743. X
  1744. X/*
  1745. X * Electric Fence confidence tests.
  1746. X * Make sure all of the various functions of Electric Fence work correctly.
  1747. X */
  1748. X
  1749. X#ifndef    PAGE_PROTECTION_VIOLATED_SIGNAL
  1750. X#define    PAGE_PROTECTION_VIOLATED_SIGNAL    SIGSEGV
  1751. X#endif
  1752. X
  1753. Xstruct diagnostic {
  1754. X    int        (*test)(void);
  1755. X    int        expectedStatus;
  1756. X    const char *    explanation;
  1757. X};
  1758. X
  1759. Xextern int    EF_PROTECT_BELOW;
  1760. Xextern int    EF_ALIGNMENT;
  1761. X
  1762. Xstatic jmp_buf    env;
  1763. X
  1764. X/*
  1765. X * There is still too little standardization of the arguments and return
  1766. X * type of signal handler functions.
  1767. X */
  1768. Xstatic
  1769. Xvoid
  1770. XsegmentationFaultHandler(
  1771. Xint signalNumber
  1772. X#if ( defined(_AIX) )
  1773. X, ...
  1774. X#endif
  1775. X)
  1776. X {
  1777. X    signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL);
  1778. X    longjmp(env, 1);
  1779. X}
  1780. X
  1781. Xstatic int
  1782. XgotSegmentationFault(int (*test)(void))
  1783. X{
  1784. X    if ( setjmp(env) == 0 ) {
  1785. X        int            status;
  1786. X
  1787. X        signal(PAGE_PROTECTION_VIOLATED_SIGNAL
  1788. X        ,segmentationFaultHandler);
  1789. X        status = (*test)();
  1790. X        signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL);
  1791. X        return status;
  1792. X    }
  1793. X    else
  1794. X        return 1;
  1795. X}
  1796. X
  1797. Xstatic char *    allocation;
  1798. X/* c is global so that assignments to it won't be optimized out. */
  1799. Xchar    c;
  1800. X
  1801. Xstatic int
  1802. XallocateMemory(void)
  1803. X{
  1804. X    allocation = (char *)malloc(1);
  1805. X
  1806. X    if ( allocation != 0 )
  1807. X        return 0;
  1808. X    else
  1809. X        return 1;
  1810. X}
  1811. X
  1812. Xstatic int
  1813. XfreeMemory(void)
  1814. X{
  1815. X    free(allocation);
  1816. X    return 0;
  1817. X}
  1818. X
  1819. Xstatic int
  1820. XprotectBelow(void)
  1821. X{
  1822. X    EF_PROTECT_BELOW = 1;
  1823. X    return 0;
  1824. X}
  1825. X
  1826. Xstatic int
  1827. Xread0(void)
  1828. X{
  1829. X    c = *allocation;
  1830. X
  1831. X    return 0;
  1832. X}
  1833. X
  1834. Xstatic int
  1835. Xwrite0(void)
  1836. X{
  1837. X    *allocation = 1;
  1838. X
  1839. X    return 0;
  1840. X}
  1841. X
  1842. Xstatic int
  1843. Xread1(void)
  1844. X{
  1845. X    c = allocation[1];
  1846. X
  1847. X    return 0;
  1848. X}
  1849. X
  1850. Xstatic int
  1851. XreadMinus1(void)
  1852. X{
  1853. X    c = allocation[-1];
  1854. X    return 0;
  1855. X}
  1856. X
  1857. Xstatic struct diagnostic diagnostics[] = {
  1858. X    {
  1859. X        allocateMemory, 0,
  1860. X        "Allocation 1: This test allocates a single byte of memory."
  1861. X    },
  1862. X    {
  1863. X        read0, 0,
  1864. X        "Read valid memory 1: This test reads the allocated memory."
  1865. X    },
  1866. X    {
  1867. X        write0, 0,
  1868. X        "Write valid memory 1: This test writes the allocated memory."
  1869. X    },
  1870. X    {
  1871. X        read1, 1,
  1872. X        "Read overrun: This test reads beyond the end of the buffer."
  1873. X    },
  1874. X    {
  1875. X        freeMemory, 0,
  1876. X        "Free memory: This test frees the allocated memory."
  1877. X    },
  1878. X    {
  1879. X        protectBelow, 0,
  1880. X        "Protect below: This sets Electric Fence to protect\n"
  1881. X        "the lower boundary of a malloc buffer, rather than the\n"
  1882. X        "upper boundary."
  1883. X    },
  1884. X    {
  1885. X        allocateMemory, 0,
  1886. X        "Allocation 2: This allocates memory with the lower boundary"
  1887. X        " protected."
  1888. X    },
  1889. X    {
  1890. X        read0, 0,
  1891. X        "Read valid memory 2: This test reads the allocated memory."
  1892. X    },
  1893. X    {
  1894. X        write0, 0,
  1895. X        "Write valid memory 2: This test writes the allocated memory."
  1896. X    },
  1897. X    {
  1898. X        readMinus1, 1,
  1899. X        "Read underrun: This test reads before the beginning of the"
  1900. X        " buffer."
  1901. X    },
  1902. X    {
  1903. X        0, 0, 0
  1904. X    }
  1905. X};
  1906. X
  1907. Xstatic const char    failedTest[]
  1908. X = "Electric Fence confidence test failed.\n";
  1909. X
  1910. Xstatic const char    newline = '\n';
  1911. X
  1912. Xint
  1913. Xmain(int argc, char * * argv)
  1914. X{
  1915. X    static const struct diagnostic *    diag = diagnostics;
  1916. X    
  1917. X
  1918. X    EF_PROTECT_BELOW = 0;
  1919. X    EF_ALIGNMENT = 0;
  1920. X
  1921. X    while ( diag->explanation != 0 ) {
  1922. X        int    status = gotSegmentationFault(diag->test);
  1923. X
  1924. X        if ( status != diag->expectedStatus ) {
  1925. X            /*
  1926. X             * Don't use stdio to print here, because stdio
  1927. X             * uses malloc() and we've just proven that malloc()
  1928. X             * is broken. Also, use _exit() instead of exit(),
  1929. X             * because _exit() doesn't flush stdio.
  1930. X             */
  1931. X            write(2, failedTest, sizeof(failedTest) - 1);
  1932. X            write(2, diag->explanation, strlen(diag->explanation));
  1933. X            write(2, &newline, 1);
  1934. X            _exit(-1);
  1935. X        }
  1936. X        diag++;
  1937. X    }
  1938. X    return 0;
  1939. X}
  1940. END_OF_FILE
  1941. if test 3490 -ne `wc -c <'eftest.c'`; then
  1942.     echo shar: \"'eftest.c'\" unpacked with wrong size!
  1943. fi
  1944. # end of 'eftest.c'
  1945. fi
  1946. if test -f 'tstheap.c' -a "${1}" != "-c" ; then 
  1947.   echo shar: Will not clobber existing file \"'tstheap.c'\"
  1948. else
  1949. echo shar: Extracting \"'tstheap.c'\" \(960 characters\)
  1950. sed "s/^X//" >'tstheap.c' <<'END_OF_FILE'
  1951. X#include <stdlib.h>
  1952. X#include <stdio.h>
  1953. X#include "efence.h"
  1954. X
  1955. X/*
  1956. X * This is a simple program to exercise the allocator. It allocates and frees
  1957. X * memory in a pseudo-random fashion. It should run silently, using up time
  1958. X * and resources on your system until you stop it or until it has gone
  1959. X * through TEST_DURATION (or the argument) iterations of the loop.
  1960. X */
  1961. X
  1962. Xextern C_LINKAGE double drand48(void); /* For pre-ANSI C systems */
  1963. X
  1964. X#define    POOL_SIZE    1024
  1965. X#define    LARGEST_BUFFER    30000
  1966. X#define    TEST_DURATION    1000000
  1967. X
  1968. Xvoid *    pool[POOL_SIZE];
  1969. X
  1970. Xint
  1971. Xmain(int argc, char * * argv)
  1972. X{
  1973. X    int    count = 0;
  1974. X    int    duration = TEST_DURATION;
  1975. X
  1976. X    if ( argc >= 2 )
  1977. X        duration = atoi(argv[1]);
  1978. X
  1979. X    for ( ; count < duration; count++ ) {
  1980. X        void * *    element = &pool[(int)(drand48() * POOL_SIZE)];
  1981. X        size_t        size = (size_t)(drand48() * (LARGEST_BUFFER+1));
  1982. X
  1983. X        if ( *element ) {
  1984. X            free( *element );
  1985. X            *element = 0;
  1986. X        }
  1987. X        else if ( size > 0 ) {
  1988. X            *element = malloc(size);
  1989. X        }
  1990. X    }
  1991. X    return 0;
  1992. X}
  1993. END_OF_FILE
  1994. if test 960 -ne `wc -c <'tstheap.c'`; then
  1995.     echo shar: \"'tstheap.c'\" unpacked with wrong size!
  1996. fi
  1997. # end of 'tstheap.c'
  1998. fi
  1999. echo shar: End of shell archive.
  2000. exit 0
  2001.