electric fence: initial checkin
authorRonald G. Minnich <rminnich@gmail.com>
Tue, 30 May 2017 15:17:30 +0000 (08:17 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 6 Jun 2017 19:48:12 +0000 (15:48 -0400)
This is from git@github.com:CheggEng/electric-fence
commit 7199c87ec6df05cff6b0faa0b7114b02b53dffe1

I did not include the debian/ directory.

Change-Id: If8a24910791fc469f4c51734cfc98471829f78d3
Signed-off-by: Ronald G. Minnich <rminnich@gmail.com>
Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
user/electric-fence/CHANGES [new file with mode: 0644]
user/electric-fence/COPYING [new file with mode: 0644]
user/electric-fence/Makefile [new file with mode: 0644]
user/electric-fence/README.md [new file with mode: 0644]
user/electric-fence/efence.c [new file with mode: 0644]
user/electric-fence/efence.h [new file with mode: 0644]
user/electric-fence/eftest.c [new file with mode: 0644]
user/electric-fence/libefence.3 [new file with mode: 0644]
user/electric-fence/page.c [new file with mode: 0644]
user/electric-fence/print.c [new file with mode: 0644]
user/electric-fence/tstheap.c [new file with mode: 0644]

diff --git a/user/electric-fence/CHANGES b/user/electric-fence/CHANGES
new file mode 100644 (file)
index 0000000..21f6c71
--- /dev/null
@@ -0,0 +1,29 @@
+2.2 25-Mar-2014
+       Added support for BSD/Mac OS, including strdup/strndup stand-ins.
+
+2.1    Remove work-arounds, most operating systems and C libraries have
+       been fixed now.
+
+2.0.1
+       Add work-arounds for kernel and library bugs under HP-UX.       
+       HP has been notified and will repair these soon.
+
+2.0.2
+       Add support for DEC Alpha. Add %a pattern for printing addresses, which
+       assumes they are passed in a void *.
+
+2.0.3 30-Sep-1993
+       When realloc is passed a zero address, it should work the same
+       way as malloc(). Fix forward declaration of mprotect() in page.c to
+       use void *, not caddr_t, for addresses. IRIX 5.0.1 complained about that.
+
+2.0.4 29-May-1994
+       Don't attempt to allow access to a zero-sized page when
+       EF_ALLOW_MALLOC_0 is set. Attempt to un-map memory from
+       Page_Delete(). If that doesn't work, fall back by protecting the
+       page from all references. Un-mapping small segments of a mapping
+       used to crash my SGI IRIX 5.0 system. I assume that nobody is running
+       5.0 any longer.
+
+2.0.5 20-January-1995
+       Port to Linux.
diff --git a/user/electric-fence/COPYING b/user/electric-fence/COPYING
new file mode 100644 (file)
index 0000000..e77696a
--- /dev/null
@@ -0,0 +1,339 @@
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/user/electric-fence/Makefile b/user/electric-fence/Makefile
new file mode 100644 (file)
index 0000000..d33e284
--- /dev/null
@@ -0,0 +1,81 @@
+ASFLAGS= -mips2
+CC= cc
+AR= ar
+INSTALL= install
+MV= mv
+CHMOD= chmod
+CFLAGS= -g
+LIB_INSTALL_DIR= /usr/lib
+MAN_INSTALL_DIR= /usr/man/man3
+
+ifeq ($(OS),Windows_NT)
+       # get a better computer
+else
+    UNAME_S := $(shell uname -s)
+    ifeq ($(UNAME_S),Darwin)
+        CFLAGS += -DPAGE_PROTECTION_VIOLATED_SIGNAL=SIGBUS
+    endif
+endif
+
+PACKAGE_SOURCE= README libefence.3 Makefile efence.h \
+       efence.c page.c print.c eftest.c tstheap.c CHANGES COPYING
+
+# Un-comment the following if you are running HP/UX.
+# CFLAGS= -Aa -g -D_HPUX_SOURCE -DPAGE_PROTECTION_VIOLATED_SIGNAL=SIGBUS
+
+# Un-comment the following if you are running AIX. This makes sure you won't
+# get the shared-library malloc() rather than the Electric Fence malloc().
+# COMPILE THE PROGRAMS YOU ARE DEBUGGING WITH THESE FLAGS, TOO.
+# CFLAGS= -g -bnso -bnodelcsect -bI:/lib/syscalls.exp
+
+# Un-comment the following if you are running SunOS 4.X
+# Note the definition of PAGE_PROTECTION_VIOLATED_SIGNAL. This may vary
+# depend on what version of Sun hardware you have.
+# You'll probably have to link the program you are debugging with -Bstatic
+# as well if using Sun's compiler, -static if using GCC.
+# CFLAGS= -g -Bstatic -DPAGE_PROTECTION_VIOLATED_SIGNAL=SIGBUS
+
+OBJECTS= efence.o page.o print.o
+
+all:   libefence.a tstheap eftest
+       @ echo
+       @ echo "Testing Electric Fence."
+       @ echo "After the last test, it should print that the test has PASSED."
+       ./eftest
+       ./tstheap 3072
+       @ echo
+       @ echo "Electric Fence confidence test PASSED." 
+       @ echo
+
+install: libefence.a libefence.3
+       $(MV) libefence.a $(LIB_INSTALL_DIR)
+       $(CHMOD) 644 $(LIB_INSTALL_DIR)/libefence.a
+       $(INSTALL) libefence.3 $(MAN_INSTALL_DIR)/libefence.3
+       $(CHMOD) 644 $(MAN_INSTALL_DIR)/libefence.3
+
+clean:
+       - rm -f $(OBJECTS) tstheap.o eftest.o tstheap eftest libefence.a \
+        libefence.cat ElectricFence.shar
+
+roff:
+       nroff -man < libefence.3 > libefence.cat
+
+
+ElectricFence.shar: $(PACKAGE_SOURCE)
+       shar $(PACKAGE_SOURCE) > ElectricFence.shar
+
+shar: ElectricFence.shar
+
+libefence.a: $(OBJECTS)
+       - rm -f libefence.a
+       $(AR) crv libefence.a $(OBJECTS)
+
+tstheap: libefence.a tstheap.o
+       - rm -f tstheap
+       $(CC) $(CFLAGS) tstheap.o libefence.a -o tstheap -lpthread
+
+eftest: libefence.a eftest.o
+       - rm -f eftest
+       $(CC) $(CFLAGS) eftest.o libefence.a -o eftest -lpthread
+
+$(OBJECTS) tstheap.o eftest.o: efence.h
diff --git a/user/electric-fence/README.md b/user/electric-fence/README.md
new file mode 100644 (file)
index 0000000..d08b7a1
--- /dev/null
@@ -0,0 +1,47 @@
+electric-fence
+==============
+This is Electric Fence 2.2 — 25-Sep-2014
+
+Electric Fence is a different kind of malloc() debugger. It uses the virtual
+memory hardware of your system to detect when software overruns the boundaries
+of a malloc() buffer. It will also detect any accesses of memory that has
+been released by free(). Because it uses the VM hardware for detection,
+Electric Fence stops your program on the first instruction that causes
+a bounds violation. It's then trivial to use a debugger to display the
+offending statement.
+
+This version will run on:
+
+       BSD and OS/X
+
+       Linux kernel version 1.1.83 and above. Earlier kernels have problems
+       with the memory protection implementation.
+
+       All System V Revision 4 platforms (and possibly earlier revisions)
+       including:
+               Every 386 System V I've heard of.
+               Solaris 2.x
+               SGI IRIX 5.0 (but not 4.x)
+
+       IBM AIX on the RS/6000.
+
+       SunOS 4.X (using an ANSI C compiler and probably static linking).
+
+       HP/UX 9.01, and possibly earlier versions.
+
+       OSF 1.3 (and possibly earlier versions) on a DECalpha.
+
+On some of these platforms, you'll have to uncomment lines in the Makefile
+that apply to your particular system, though it would be better if someone
+added a better build-system so that this was not necessary.
+
+If you test Electric Fence on a platform not mentioned here, please send me a
+report.
+
+It will probably port to any ANSI/POSIX system that provides mmap(), and
+mprotect(), as long as mprotect() has the capability to turn off all access
+to a memory page, and mmap() can use /dev/zero or the MAP_ANONYMOUS flag
+to create virtual memory pages.
+
+Complete information on the use of Electric Fence is in the manual page
+libefence.3 .  You can read it with "man ./libefence.3".
diff --git a/user/electric-fence/efence.c b/user/electric-fence/efence.c
new file mode 100644 (file)
index 0000000..0a0d506
--- /dev/null
@@ -0,0 +1,895 @@
+/*
+ * Electric Fence - Red-Zone memory allocator.
+ * Bruce Perens, 1988, 1993
+ * 
+ * For email below, drop spaces and <spam-buster> tag.
+ * MODIFIED:  March 20, 2014 (jric<spam-buster> @ <spam-buster> chegg DOT com)
+ *
+ * This is a special version of malloc() and company for debugging software
+ * that is suspected of overrunning or underrunning the boundaries of a
+ * malloc buffer, or touching free memory.
+ *
+ * It arranges for each malloc buffer to be followed (or preceded)
+ * in the address space by an inaccessable virtual memory page,
+ * and for free memory to be inaccessable. If software touches the
+ * inaccessable page, it will get an immediate segmentation
+ * fault. It is then trivial to uncover the offending code using a debugger.
+ *
+ * An advantage of this product over most malloc debuggers is that this one
+ * detects reading out of bounds as well as writing, and this one stops on
+ * the exact instruction that causes the error, rather than waiting until the
+ * next boundary check.
+ *
+ * There is one product that debugs malloc buffer overruns
+ * better than Electric Fence: "Purify" from Purify Systems, and that's only
+ * a small part of what Purify does. I'm not affiliated with Purify, I just
+ * respect a job well done.
+ *
+ * This version of malloc() should not be linked into production software,
+ * since it tremendously increases the time and memory overhead of malloc().
+ * Each malloc buffer will consume a minimum of two virtual memory pages,
+ * this is 16 kilobytes on many systems. On some systems it will be necessary
+ * to increase the amount of swap space in order to debug large programs that
+ * perform lots of allocation, because of the per-buffer overhead.
+ *
+ */
+#include "efence.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <memory.h>
+#include <string.h>
+#include <pthread.h>
+#include <errno.h>
+
+#ifdef malloc
+#undef malloc
+#endif
+
+#ifdef calloc
+#undef calloc
+#endif
+
+static const char      version[] = "\n  Electric Fence 2.2"
+ " Copyright (C) 1987-2014 Bruce Perens.\n";
+
+/*
+ * MEMORY_CREATION_SIZE is the amount of memory to get from the operating
+ * system at one time. We'll break that memory down into smaller pieces for
+ * malloc buffers. One megabyte is probably a good value.
+ */
+#define                        MEMORY_CREATION_SIZE    1024 * 1024
+
+/*
+ * Enum Mode indicates the status of a malloc buffer.
+ */
+enum _Mode {
+       NOT_IN_USE = 0, /* Available to represent a malloc buffer. */
+       FREE,           /* A free buffer. */
+       ALLOCATED,      /* A buffer that is in use. */
+       PROTECTED,      /* A freed buffer that can not be allocated again. */
+       INTERNAL_USE    /* A buffer used internally by malloc(). */
+};
+typedef enum _Mode     Mode;
+
+/*
+ * Struct Slot contains all of the information about a malloc buffer except
+ * for the contents of its memory.
+ */
+struct _Slot {
+       void *          userAddress;
+       void *          internalAddress;
+       size_t          userSize;
+       size_t          internalSize;
+       Mode            mode;
+};
+typedef struct _Slot   Slot;
+
+ /*
+ * EF_DISABLE_BANNER is a global variable used to control whether
+ * Electric Fence prints its usual startup message.  If the value is
+ * -1, it will be set from the environment default to 0 at run time.
+ */
+int            EF_DISABLE_BANNER = -1;
+
+
+/*
+ * EF_ALIGNMENT is a global variable used to control the default alignment
+ * of buffers returned by malloc(), calloc(), and realloc(). It is all-caps
+ * so that its name matches the name of the environment variable that is used
+ * to set it. This gives the programmer one less name to remember.
+ * If the value is -1, it will be set from the environment or sizeof(int)
+ * at run time.
+ */
+int            EF_ALIGNMENT = -1;
+
+/*
+ * EF_PROTECT_FREE is a global variable used to control the disposition of
+ * memory that is released using free(). It is all-caps so that its name
+ * matches the name of the environment variable that is used to set it.
+ * If its value is greater non-zero, memory released by free is made
+ * inaccessable and never allocated again. Any software that touches free
+ * memory will then get a segmentation fault. If its value is zero, freed
+ * memory will be available for reallocation, but will still be inaccessable
+ * until it is reallocated.
+ * If the value is -1, it will be set from the environment or to 0 at run-time.
+ */
+int            EF_PROTECT_FREE = -1;
+
+/*
+ * EF_PROTECT_BELOW is used to modify the behavior of the allocator. When
+ * its value is non-zero, the allocator will place an inaccessable page
+ * immediately _before_ the malloc buffer in the address space, instead
+ * of _after_ it. Use this to detect malloc buffer under-runs, rather than
+ * over-runs. It won't detect both at the same time, so you should test your
+ * software twice, once with this value clear, and once with it set.
+ * If the value is -1, it will be set from the environment or to zero at
+ * run-time
+ */
+int            EF_PROTECT_BELOW = -1;
+
+/*
+ * EF_ALLOW_MALLOC_0 is set if Electric Fence is to allow malloc(0). I
+ * trap malloc(0) by default because it is a common source of bugs.
+ */
+int            EF_ALLOW_MALLOC_0 = -1;
+
+/*
+ * EF_FREE_WIPES is set if Electric Fence is to wipe the memory content
+ * of freed blocks.  This makes it easier to check if memory is freed or
+ * not
+ */
+int            EF_FREE_WIPES = -1;
+
+/*
+ * allocationList points to the array of slot structures used to manage the
+ * malloc arena.
+ */
+static Slot *          allocationList = 0;
+
+/*
+ * allocationListSize is the size of the allocation list. This will always
+ * be a multiple of the page size.
+ */
+static size_t          allocationListSize = 0;
+
+/*
+ * slotCount is the number of Slot structures in allocationList.
+ */
+static size_t          slotCount = 0;
+
+/*
+ * unUsedSlots is the number of Slot structures that are currently available
+ * to represent new malloc buffers. When this number gets too low, we will
+ * create new slots.
+ */
+static size_t          unUsedSlots = 0;
+
+/*
+ * slotsPerPage is the number of slot structures that fit in a virtual
+ * memory page.
+ */
+static size_t          slotsPerPage = 0;
+
+/*
+ * internalUse is set when allocating and freeing the allocatior-internal
+ * data structures.
+ */
+static int             internalUse = 0;
+
+/*
+ * noAllocationListProtection is set to tell malloc() and free() not to
+ * manipulate the protection of the allocation list. This is only set in
+ * realloc(), which does it to save on slow system calls, and in
+ * allocateMoreSlots(), which does it because it changes the allocation list.
+ */
+static int             noAllocationListProtection = 0;
+
+/*
+ * bytesPerPage is set at run-time to the number of bytes per virtual-memory
+ * page, as returned by Page_Size().
+ */
+static size_t          bytesPerPage = 0;
+
+ /*
+ * mutex to enable multithreaded operation
+ */
+static pthread_mutex_t mutex ;
+static pid_t mutexpid=0;
+static int locknr=0;
+
+
+static void lock() {
+    if (pthread_mutex_trylock(&mutex)) {
+       if (mutexpid==getpid()) {
+           locknr++;
+           return;
+       } else {
+           pthread_mutex_lock(&mutex);
+       }
+    } 
+    mutexpid=getpid();
+    locknr=1;
+}
+
+static void unlock() {
+    locknr--;
+    if (!locknr) {
+       mutexpid=0;
+       pthread_mutex_unlock(&mutex);
+    }
+}
+
+/*
+ * internalError is called for those "shouldn't happen" errors in the
+ * allocator.
+ */
+static void
+internalError(void)
+{
+       EF_Abort("Internal error in allocator.");
+}
+
+/*
+ * initialize sets up the memory allocation arena and the run-time
+ * configuration information.
+ */
+static void
+initialize(void)
+{
+       size_t  size = MEMORY_CREATION_SIZE;
+       size_t  slack;
+       char *  string;
+       Slot *  slot;
+
+       if ( EF_DISABLE_BANNER == -1 ) {
+               if ( (string = getenv("EF_DISABLE_BANNER")) != 0 )
+                       EF_DISABLE_BANNER = atoi(string);
+               else
+                       EF_DISABLE_BANNER = 0;
+       }
+
+       if ( EF_DISABLE_BANNER == 0 )
+               EF_Print(version);
+
+       /*
+        * Import the user's environment specification of the default
+        * alignment for malloc(). We want that alignment to be under
+        * user control, since smaller alignment lets us catch more bugs,
+        * however some software will break if malloc() returns a buffer
+        * that is not word-aligned.
+        *
+        * I would like
+        * alignment to be zero so that we could catch all one-byte
+        * overruns, however if malloc() is asked to allocate an odd-size
+        * buffer and returns an address that is not word-aligned, or whose
+        * size is not a multiple of the word size, software breaks.
+        * This was the case with the Sun string-handling routines,
+        * which can do word fetches up to three bytes beyond the end of a
+        * string. I handle this problem in part by providing
+        * byte-reference-only versions of the string library functions, but
+        * there are other functions that break, too. Some in X Windows, one
+        * in Sam Leffler's TIFF library, and doubtless many others.
+        */
+       if ( EF_ALIGNMENT == -1 ) {
+               if ( (string = getenv("EF_ALIGNMENT")) != 0 )
+                       EF_ALIGNMENT = (size_t)atoi(string);
+               else
+                       EF_ALIGNMENT = sizeof(int);
+       }
+
+       /*
+        * See if the user wants to protect the address space below a buffer,
+        * rather than that above a buffer.
+        */
+       if ( EF_PROTECT_BELOW == -1 ) {
+               if ( (string = getenv("EF_PROTECT_BELOW")) != 0 )
+                       EF_PROTECT_BELOW = (atoi(string) != 0);
+               else
+                       EF_PROTECT_BELOW = 0;
+       }
+
+       /*
+        * See if the user wants to protect memory that has been freed until
+        * the program exits, rather than until it is re-allocated.
+        */
+       if ( EF_PROTECT_FREE == -1 ) {
+               if ( (string = getenv("EF_PROTECT_FREE")) != 0 )
+                       EF_PROTECT_FREE = (atoi(string) != 0);
+               else
+                       EF_PROTECT_FREE = 0;
+       }
+
+       /*
+        * See if the user wants to allow malloc(0).
+        */
+       if ( EF_ALLOW_MALLOC_0 == -1 ) {
+               if ( (string = getenv("EF_ALLOW_MALLOC_0")) != 0 )
+                       EF_ALLOW_MALLOC_0 = (atoi(string) != 0);
+               else
+                       EF_ALLOW_MALLOC_0 = 0;
+       }
+
+       /*
+        * See if the user wants us to wipe out freed memory.
+        */
+       if ( EF_FREE_WIPES == -1 ) {
+               if ( (string = getenv("EF_FREE_WIPES")) != 0 )
+                       EF_FREE_WIPES = (atoi(string) != 0);
+               else
+                       EF_FREE_WIPES = 0;
+       }
+
+       /*
+        * Get the run-time configuration of the virtual memory page size.
+        */
+       bytesPerPage = Page_Size();
+
+       /*
+        * Figure out how many Slot structures to allocate at one time.
+        */
+       slotCount = slotsPerPage = bytesPerPage / sizeof(Slot);
+       allocationListSize = bytesPerPage;
+
+       if ( allocationListSize > size )
+               size = allocationListSize;
+
+       if ( (slack = size % bytesPerPage) != 0 )
+               size += bytesPerPage - slack;
+
+       /*
+        * Allocate memory, and break it up into two malloc buffers. The
+        * first buffer will be used for Slot structures, the second will
+        * be marked free.
+        */
+       slot = allocationList = (Slot *)Page_Create(size);
+       memset((char *)allocationList, 0, allocationListSize);
+
+       slot[0].internalSize = slot[0].userSize = allocationListSize;
+       slot[0].internalAddress = slot[0].userAddress = allocationList;
+       slot[0].mode = INTERNAL_USE;
+       if ( size > allocationListSize ) {
+               slot[1].internalAddress = slot[1].userAddress
+                = ((char *)slot[0].internalAddress) + slot[0].internalSize;
+               slot[1].internalSize
+                = slot[1].userSize = size - slot[0].internalSize;
+               slot[1].mode = FREE;
+       }
+
+       /*
+        * Deny access to the free page, so that we will detect any software
+        * that treads upon free memory.
+        */
+       Page_DenyAccess(slot[1].internalAddress, slot[1].internalSize);
+
+       /*
+        * Account for the two slot structures that we've used.
+        */
+       unUsedSlots = slotCount - 2;
+}
+
+/*
+ * allocateMoreSlots is called when there are only enough slot structures
+ * left to support the allocation of a single malloc buffer.
+ */
+static void
+allocateMoreSlots(void)
+{
+       size_t  newSize = allocationListSize + bytesPerPage;
+       void *  newAllocation;
+       void *  oldAllocation = allocationList;
+
+       Page_AllowAccess(allocationList, allocationListSize);
+       noAllocationListProtection = 1;
+       internalUse = 1;
+
+       newAllocation = malloc(newSize);
+       memcpy(newAllocation, allocationList, allocationListSize);
+       memset(&(((char *)newAllocation)[allocationListSize]), 0, bytesPerPage);
+
+       allocationList = (Slot *)newAllocation;
+       allocationListSize = newSize;
+       slotCount += slotsPerPage;
+       unUsedSlots += slotsPerPage;
+
+       free(oldAllocation);
+
+       /*
+        * Keep access to the allocation list open at this point, because
+        * I am returning to memalign(), which needs that access.
+        */
+       noAllocationListProtection = 0;
+       internalUse = 0;
+}
+
+/*
+ * This is the memory allocator. When asked to allocate a buffer, allocate
+ * it in such a way that the end of the buffer is followed by an inaccessable
+ * memory page. If software overruns that buffer, it will touch the bad page
+ * and get an immediate segmentation fault. It's then easy to zero in on the
+ * offending code with a debugger.
+ *
+ * There are a few complications. If the user asks for an odd-sized buffer,
+ * we would have to have that buffer start on an odd address if the byte after
+ * the end of the buffer was to be on the inaccessable page. Unfortunately,
+ * there is lots of software that asks for odd-sized buffers and then
+ * requires that the returned address be word-aligned, or the size of the
+ * buffer be a multiple of the word size. An example are the string-processing
+ * functions on Sun systems, which do word references to the string memory
+ * and may refer to memory up to three bytes beyond the end of the string.
+ * For this reason, I take the alignment requests to memalign() and valloc()
+ * seriously, and 
+ * 
+ * Electric Fence wastes lots of memory. I do a best-fit allocator here
+ * so that it won't waste even more. It's slow, but thrashing because your
+ * working set is too big for a system's RAM is even slower. 
+ */
+extern C_LINKAGE void *
+memalign(size_t alignment, size_t userSize)
+{
+       register Slot * slot;
+       register size_t count;
+       Slot *          fullSlot = 0;
+       Slot *          emptySlots[2];
+       size_t          internalSize;
+       size_t          slack;
+       char *          address;
+
+       if ( allocationList == 0 )
+               initialize();
+
+       if ( userSize == 0 && !EF_ALLOW_MALLOC_0 )
+               EF_Abort("Allocating 0 bytes, probably a bug.");
+
+       /*
+        * If EF_PROTECT_BELOW is set, all addresses returned by malloc()
+        * and company will be page-aligned.
+        */
+       if ( !EF_PROTECT_BELOW && alignment > 1 ) {
+               if ( (slack = userSize % alignment) != 0 )
+                       userSize += alignment - slack;
+       }
+
+       /*
+        * The internal size of the buffer is rounded up to the next page-size
+        * boudary, and then we add another page's worth of memory for the
+        * dead page.
+        */
+       internalSize = userSize + bytesPerPage;
+       if ( (slack = internalSize % bytesPerPage) != 0 )
+               internalSize += bytesPerPage - slack;
+
+       /*
+        * These will hold the addresses of two empty Slot structures, that
+        * can be used to hold information for any memory I create, and any
+        * memory that I mark free.
+        */
+       emptySlots[0] = 0;
+       emptySlots[1] = 0;
+
+       /*
+        * The internal memory used by the allocator is currently
+        * inaccessable, so that errant programs won't scrawl on the
+        * allocator's arena. I'll un-protect it here so that I can make
+        * a new allocation. I'll re-protect it before I return.
+        */
+       if ( !noAllocationListProtection )
+               Page_AllowAccess(allocationList, allocationListSize);
+
+       /*
+        * If I'm running out of empty slots, create some more before
+        * I don't have enough slots left to make an allocation.
+        */
+       if ( !internalUse && unUsedSlots < 7 ) {
+               allocateMoreSlots();
+       }
+       
+       /*
+        * Iterate through all of the slot structures. Attempt to find a slot
+        * containing free memory of the exact right size. Accept a slot with
+        * more memory than we want, if the exact right size is not available.
+        * Find two slot structures that are not in use. We will need one if
+        * we split a buffer into free and allocated parts, and the second if
+        * we have to create new memory and mark it as free.
+        *
+        */
+       
+       for ( slot = allocationList, count = slotCount ; count > 0; count-- ) {
+               if ( slot->mode == FREE
+                && slot->internalSize >= internalSize ) {
+                       if ( !fullSlot
+                        ||slot->internalSize < fullSlot->internalSize){
+                               fullSlot = slot;
+                               if ( slot->internalSize == internalSize
+                                && emptySlots[0] )
+                                       break;  /* All done, */
+                       }
+               }
+               else if ( slot->mode == NOT_IN_USE ) {
+                       if ( !emptySlots[0] )
+                               emptySlots[0] = slot;
+                       else if ( !emptySlots[1] )
+                               emptySlots[1] = slot;
+                       else if ( fullSlot
+                        && fullSlot->internalSize == internalSize )
+                               break;  /* All done. */
+               }
+               slot++;
+       }
+       if ( !emptySlots[0] )
+               internalError();
+
+       if ( !fullSlot ) {
+               /*
+                * I get here if I haven't been able to find a free buffer
+                * with all of the memory I need. I'll have to create more
+                * memory. I'll mark it all as free, and then split it into
+                * free and allocated portions later.
+                */
+               size_t  chunkSize = MEMORY_CREATION_SIZE;
+
+               if ( !emptySlots[1] )
+                       internalError();
+
+               if ( chunkSize < internalSize )
+                       chunkSize = internalSize;
+
+               if ( (slack = chunkSize % bytesPerPage) != 0 )
+                       chunkSize += bytesPerPage - slack;
+
+               /* Use up one of the empty slots to make the full slot. */
+               fullSlot = emptySlots[0];
+               emptySlots[0] = emptySlots[1];
+               fullSlot->internalAddress = Page_Create(chunkSize);
+               fullSlot->internalSize = chunkSize;
+               fullSlot->mode = FREE;
+               unUsedSlots--;
+       }
+
+       /*
+        * If I'm allocating memory for the allocator's own data structures,
+        * mark it INTERNAL_USE so that no errant software will be able to
+        * free it.
+        */
+       if ( internalUse )
+               fullSlot->mode = INTERNAL_USE;
+       else
+               fullSlot->mode = ALLOCATED;
+
+       /*
+        * If the buffer I've found is larger than I need, split it into
+        * an allocated buffer with the exact amount of memory I need, and
+        * a free buffer containing the surplus memory.
+        */
+       if ( fullSlot->internalSize > internalSize ) {
+               emptySlots[0]->internalSize
+                = fullSlot->internalSize - internalSize;
+               emptySlots[0]->internalAddress
+                = ((char *)fullSlot->internalAddress) + internalSize;
+               emptySlots[0]->mode = FREE;
+               fullSlot->internalSize = internalSize;
+               unUsedSlots--;
+       }
+
+       if ( !EF_PROTECT_BELOW ) {
+               /*
+                * Arrange the buffer so that it is followed by an inaccessable
+                * memory page. A buffer overrun that touches that page will
+                * cause a segmentation fault.
+                */
+               address = (char *)fullSlot->internalAddress;
+
+               /* Set up the "live" page. */
+               if ( internalSize - bytesPerPage > 0 )
+                               Page_AllowAccess(
+                                fullSlot->internalAddress
+                               ,internalSize - bytesPerPage);
+                       
+               address += internalSize - bytesPerPage;
+
+               /* Set up the "dead" page. */
+               Page_DenyAccess(address, bytesPerPage);
+
+               /* Figure out what address to give the user. */
+               address -= userSize;
+       }
+       else {  /* EF_PROTECT_BELOW != 0 */
+               /*
+                * Arrange the buffer so that it is preceded by an inaccessable
+                * memory page. A buffer underrun that touches that page will
+                * cause a segmentation fault.
+                */
+               address = (char *)fullSlot->internalAddress;
+
+               /* Set up the "dead" page. */
+               Page_DenyAccess(address, bytesPerPage);
+                       
+               address += bytesPerPage;
+
+               /* Set up the "live" page. */
+               if ( internalSize - bytesPerPage > 0 )
+                       Page_AllowAccess(address, internalSize - bytesPerPage);
+       }
+
+       fullSlot->userAddress = address;
+       fullSlot->userSize = userSize;
+
+       /*
+        * Make the pool's internal memory inaccessable, so that the program
+        * being debugged can't stomp on it.
+        */
+       if ( !internalUse )
+               Page_DenyAccess(allocationList, allocationListSize);
+
+       return address;
+}
+
+/*
+ * Find the slot structure for a user address.
+ */
+static Slot *
+slotForUserAddress(void * address)
+{
+       register Slot * slot = allocationList;
+       register size_t count = slotCount;
+       
+       for ( ; count > 0; count-- ) {
+               if ( slot->userAddress == address )
+                       return slot;
+               slot++;
+       }
+
+       return 0;
+}
+
+/*
+ * Find the slot structure for an internal address.
+ */
+static Slot *
+slotForInternalAddress(void * address)
+{
+       register Slot * slot = allocationList;
+       register size_t count = slotCount;
+       
+       for ( ; count > 0; count-- ) {
+               if ( slot->internalAddress == address )
+                       return slot;
+               slot++;
+       }
+       return 0;
+}
+
+/*
+ * Given the internal address of a buffer, find the buffer immediately
+ * before that buffer in the address space. This is used by free() to
+ * coalesce two free buffers into one.
+ */
+static Slot *
+slotForInternalAddressPreviousTo(void * address)
+{
+       register Slot * slot = allocationList;
+       register size_t count = slotCount;
+       
+       for ( ; count > 0; count-- ) {
+               if ( ((char *)slot->internalAddress)
+                + slot->internalSize == address )
+                       return slot;
+               slot++;
+       }
+       return 0;
+}
+
+extern C_LINKAGE void
+free(void * address)
+{
+       Slot *  slot;
+       Slot *  previousSlot = 0;
+       Slot *  nextSlot = 0;
+
+        lock();
+
+        if ( address == 0 ) {
+                unlock();
+                return;
+        }
+
+       if ( allocationList == 0 )
+               EF_Abort("free() called before first malloc().");
+
+       if ( !noAllocationListProtection )
+               Page_AllowAccess(allocationList, allocationListSize);
+
+       slot = slotForUserAddress(address);
+
+       if ( !slot )
+               EF_Abort("free(%a): address not from malloc().", address);
+
+       if ( slot->mode != ALLOCATED ) {
+               if ( internalUse && slot->mode == INTERNAL_USE )
+                       /* Do nothing. */;
+               else {
+                       EF_Abort(
+                        "free(%a): freeing free memory."
+                       ,address);
+               }
+       }
+
+       if ( EF_PROTECT_FREE )
+               slot->mode = PROTECTED;
+       else
+               slot->mode = FREE;
+
+       if ( EF_FREE_WIPES )
+               memset(slot->userAddress, 0xbd, slot->userSize);
+
+       previousSlot = slotForInternalAddressPreviousTo(slot->internalAddress);
+       nextSlot = slotForInternalAddress(
+        ((char *)slot->internalAddress) + slot->internalSize);
+
+       if ( previousSlot
+        && (previousSlot->mode == FREE || previousSlot->mode == PROTECTED) ) {
+               /* Coalesce previous slot with this one. */
+               previousSlot->internalSize += slot->internalSize;
+               if ( EF_PROTECT_FREE )
+                       previousSlot->mode = PROTECTED;
+
+               slot->internalAddress = slot->userAddress = 0;
+               slot->internalSize = slot->userSize = 0;
+               slot->mode = NOT_IN_USE;
+               slot = previousSlot;
+               unUsedSlots++;
+       }
+       if ( nextSlot
+        && (nextSlot->mode == FREE || nextSlot->mode == PROTECTED) ) {
+               /* Coalesce next slot with this one. */
+               slot->internalSize += nextSlot->internalSize;
+               nextSlot->internalAddress = nextSlot->userAddress = 0;
+               nextSlot->internalSize = nextSlot->userSize = 0;
+               nextSlot->mode = NOT_IN_USE;
+               unUsedSlots++;
+       }
+
+       slot->userAddress = slot->internalAddress;
+       slot->userSize = slot->internalSize;
+
+       /*
+        * Free memory is _always_ set to deny access. When EF_PROTECT_FREE
+        * is true, free memory is never reallocated, so it remains access
+        * denied for the life of the process. When EF_PROTECT_FREE is false, 
+        * the memory may be re-allocated, at which time access to it will be
+        * allowed again.
+        */
+       Page_DenyAccess(slot->internalAddress, slot->internalSize);
+
+       if ( !noAllocationListProtection )
+               Page_DenyAccess(allocationList, allocationListSize);
+
+        unlock();
+}
+
+extern C_LINKAGE void *
+realloc(void * oldBuffer, size_t newSize)
+{
+       void *  newBuffer = malloc(newSize);
+
+        lock();
+
+       if ( oldBuffer ) {
+               size_t  size;
+               Slot *  slot;
+
+               Page_AllowAccess(allocationList, allocationListSize);
+               noAllocationListProtection = 1;
+               
+               slot = slotForUserAddress(oldBuffer);
+
+               if ( slot == 0 )
+                       EF_Abort(
+                        "realloc(%a, %d): address not from malloc()."
+                       ,oldBuffer
+                       ,newSize);
+
+               if ( newSize < (size = slot->userSize) )
+                       size = newSize;
+
+               if ( size > 0 )
+                       memcpy(newBuffer, oldBuffer, size);
+
+               free(oldBuffer);
+               noAllocationListProtection = 0;
+               Page_DenyAccess(allocationList, allocationListSize);
+
+               if ( size < newSize )
+                       memset(&(((char *)newBuffer)[size]), 0, newSize - size);
+               
+               /* Internal memory was re-protected in free() */
+       }
+       unlock();
+
+       return newBuffer;
+}
+
+extern C_LINKAGE void *
+malloc(size_t size)
+{
+        void  *allocation;   
+        if ( allocationList == 0 ) {
+                pthread_mutex_init(&mutex, NULL); 
+                initialize();   /* This sets EF_ALIGNMENT */
+        }       
+        lock();
+        allocation=memalign(EF_ALIGNMENT, size); 
+
+        unlock();
+
+       return allocation;
+}
+
+extern C_LINKAGE char *
+strdup(const char *s1)
+{
+        if (!s1) return 0;
+        char *s2 = malloc(strlen(s1) + 1);
+
+        if (!s2) {
+                errno = ENOMEM;
+                return 0;
+        }
+
+        return strcpy(s2, s1);
+}
+
+extern C_LINKAGE char *
+strndup(const char *s1, size_t n)
+{
+        if (!s1) return 0;
+        int complete_size = n;  /* includes terminating null */
+        for (int i = 0; i < n - 1; i++) {
+                if (!s1[i]) {
+                        complete_size = i + 2;
+                        break;
+                }
+        }
+        char *s2 = malloc(complete_size);
+
+        if (!s2) {
+                errno = ENOMEM;
+                return 0;
+        }
+
+        strncpy(s2, s1, complete_size - 1);
+        s2[complete_size - 1] = '\0';
+
+        return s2;
+}
+
+extern C_LINKAGE void *
+calloc(size_t nelem, size_t elsize)
+{
+       size_t  size = nelem * elsize;
+        void * allocation;
+        
+        lock();
+       
+        allocation = malloc(size);
+        memset(allocation, 0, size);
+        unlock();
+
+       return allocation;
+}
+
+/*
+ * This will catch more bugs if you remove the page alignment, but it
+ * will break some software.
+ */
+extern C_LINKAGE void *
+valloc (size_t size)
+{
+        void * allocation;
+       
+        lock();
+        allocation= memalign(bytesPerPage, size);
+        unlock();
+       
+        return allocation;
+}
diff --git a/user/electric-fence/efence.h b/user/electric-fence/efence.h
new file mode 100644 (file)
index 0000000..60eb30f
--- /dev/null
@@ -0,0 +1,42 @@
+#include <sys/types.h>
+#include <sys/param.h>
+
+/*
+ * ef_number is the largest unsigned integer we'll need. On systems that
+ * support 64-bit pointers, this may be "unsigned long long".
+ */
+#if defined(USE_LONG_LONG)
+typedef unsigned long long     ef_number;
+#else
+typedef unsigned long          ef_number;
+#endif
+
+/*
+ * NBBY is the number of bits per byte. Some systems define it in
+ * <sys/param.h> .
+ */
+#ifndef        NBBY
+#define        NBBY    8
+#endif
+
+/*
+ * This is used to declare functions with "C" linkage if we are compiling
+ * with C++ .
+ */
+#ifdef __cplusplus
+#define        C_LINKAGE       "C"
+#else
+#define        C_LINKAGE
+#endif
+
+void                   Page_AllowAccess(void * address, size_t size);
+void *                 Page_Create(size_t size);
+void                   Page_Delete(void * address, size_t size);
+void                   Page_DenyAccess(void * address, size_t size);
+size_t                 Page_Size(void);
+
+void                   EF_Abort(const char * message, ...);
+void                   EF_Exit(const char * message, ...);
+void                   EF_Print(const char * message, ...);
+void                   EF_Lock();
+void                   EF_UnLock();
diff --git a/user/electric-fence/eftest.c b/user/electric-fence/eftest.c
new file mode 100644 (file)
index 0000000..372ac59
--- /dev/null
@@ -0,0 +1,219 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <setjmp.h>
+#include <signal.h>
+#include "efence.h"
+
+/*
+ * Electric Fence confidence tests.
+ * Make sure all of the various functions of Electric Fence work correctly.
+ */
+
+#ifndef        PAGE_PROTECTION_VIOLATED_SIGNAL
+#define        PAGE_PROTECTION_VIOLATED_SIGNAL SIGSEGV
+#endif
+
+struct diagnostic {
+       int             (*test)(void);
+       int             expectedStatus;
+       const char *    explanation;
+};
+
+extern int     EF_PROTECT_BELOW;
+extern int     EF_ALIGNMENT;
+
+static sigjmp_buf      env;
+
+/*
+ * There is still too little standardization of the arguments and return
+ * type of signal handler functions.
+ */
+static
+void
+segmentationFaultHandler(
+int signalNumber
+#if ( defined(_AIX) )
+, ...
+#endif
+)
+ {
+       signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL);
+       siglongjmp(env, 1);
+}
+
+static int
+gotSegmentationFault(int (*test)(void))
+{
+       if ( sigsetjmp(env,1) == 0 ) {
+               int                     status;
+
+               signal(PAGE_PROTECTION_VIOLATED_SIGNAL
+               ,segmentationFaultHandler);
+               status = (*test)();
+               signal(PAGE_PROTECTION_VIOLATED_SIGNAL, SIG_DFL);
+               return status;
+       }
+       else
+               return 1;
+}
+
+static char *  allocation;
+/* c is global so that assignments to it won't be optimized out. */
+char   c;
+
+static int
+testSizes(void)
+{
+       /*
+        * If ef_number can't hold all of the bits of a void *, have the user
+        * add -DUSE_ LONG_LONG to the compiler flags so that ef_number will be
+        * declared as "unsigned long long" instead of "unsigned long".
+        */
+       return ( sizeof(ef_number) < sizeof(void *) );
+}
+
+static int
+allocateMemory(void)
+{
+       allocation = (char *)malloc(1);
+
+       if ( allocation != 0 )
+               return 0;
+       else
+               return 1;
+}
+
+static int
+freeMemory(void)
+{
+       free(allocation);
+       return 0;
+}
+
+static int
+protectBelow(void)
+{
+       EF_PROTECT_BELOW = 1;
+       return 0;
+}
+
+static int
+read0(void)
+{
+       c = *allocation;
+
+       return 0;
+}
+
+static int
+write0(void)
+{
+       *allocation = 1;
+
+       return 0;
+}
+
+static int
+read1(void)
+{
+       c = allocation[1];
+
+       return 0;
+}
+
+static int
+readMinus1(void)
+{
+       c = allocation[-1];
+       return 0;
+}
+
+static struct diagnostic diagnostics[] = {
+       {
+               testSizes, 0,
+               "Please add -DLONG_LONG to the compiler flags and recompile."
+       },
+       {
+               allocateMemory, 0,
+               "Allocation 1: This test allocates a single byte of memory."
+       },
+       {
+               read0, 0,
+               "Read valid memory 1: This test reads the allocated memory."
+       },
+       {
+               write0, 0,
+               "Write valid memory 1: This test writes the allocated memory."
+       },
+       {
+               read1, 1,
+               "Read overrun: This test reads beyond the end of the buffer."
+       },
+       {
+               freeMemory, 0,
+               "Free memory: This test frees the allocated memory."
+       },
+       {
+               protectBelow, 0,
+               "Protect below: This sets Electric Fence to protect\n"
+               "the lower boundary of a malloc buffer, rather than the\n"
+               "upper boundary."
+       },
+       {
+               allocateMemory, 0,
+               "Allocation 2: This allocates memory with the lower boundary"
+               " protected."
+       },
+       {
+               read0, 0,
+               "Read valid memory 2: This test reads the allocated memory."
+       },
+       {
+               write0, 0,
+               "Write valid memory 2: This test writes the allocated memory."
+       },
+       {
+               readMinus1, 1,
+               "Read underrun: This test reads before the beginning of the"
+               " buffer."
+       },
+       {
+               0, 0, 0
+       }
+};
+
+static const char      failedTest[]
+ = "Electric Fence confidence test failed.\n";
+
+static const char      newline = '\n';
+
+int
+main(int argc, char * * argv)
+{
+       static const struct diagnostic *        diag = diagnostics;
+       
+
+       EF_PROTECT_BELOW = 0;
+       EF_ALIGNMENT = 0;
+
+       while ( diag->explanation != 0 ) {
+               int     status = gotSegmentationFault(diag->test);
+
+               if ( status != diag->expectedStatus ) {
+                       /*
+                        * Don't use stdio to print here, because stdio
+                        * uses malloc() and we've just proven that malloc()
+                        * is broken. Also, use _exit() instead of exit(),
+                        * because _exit() doesn't flush stdio.
+                        */
+                       write(2, failedTest, sizeof(failedTest) - 1);
+                       write(2, diag->explanation, strlen(diag->explanation));
+                       write(2, &newline, 1);
+                       _exit(-1);
+               }
+               diag++;
+       }
+       return 0;
+}
diff --git a/user/electric-fence/libefence.3 b/user/electric-fence/libefence.3
new file mode 100644 (file)
index 0000000..e2d76d6
--- /dev/null
@@ -0,0 +1,415 @@
+.TH efence 3 27-April-1993
+.SH NAME
+efence \- Electric Fence Malloc Debugger
+.SH SYNOPSIS
+.nf
+.ft B
+#include <stdlib.h>
+.ft
+.fi
+.LP
+.nf
+.ft B
+void * malloc (size_t size);
+.ft
+.fi
+.LP
+.nf
+.ft B
+void free (void *ptr);
+.ft
+.fi
+.LP
+.nf
+.ft B
+void * realloc (void *ptr, size_t size);
+.ft
+.fi
+.LP
+.nf
+.ft B
+void * calloc (size_t nelem, size_t elsize);
+.ft
+.fi
+.LP
+.nf
+.ft B
+void * memalign (size_t alignment, size_t size);
+.ft
+.fi
+.LP
+.nf
+.ft B
+void * valloc (size_t size);
+.ft
+.fi
+.LP
+.nf
+.ft B
+extern int EF_DISABLE_BANNER;
+.ft
+.fi
+.LP
+.nf
+.ft B
+extern int EF_ALIGNMENT;
+.ft
+.fi
+.LP
+.nf
+.ft B
+extern int EF_PROTECT_BELOW;
+.ft
+.fi
+.LP
+.nf
+.ft B
+extern int EF_PROTECT_FREE;
+.ft
+.fi
+.LP
+.nf
+.ft B
+extern int EF_ALLOW_MALLOC_0;
+.ft
+.fi
+.LP
+.nf
+.ft B
+extern int EF_FREE_WIPES;
+.ft
+.fi
+.SH DESCRIPTION
+.I Electric Fence
+helps you detect two common programming bugs:
+software that overruns the boundaries of a malloc() memory
+allocation, and software that touches a memory allocation that has been
+released by free(). Unlike other malloc() debuggers, Electric Fence will
+detect
+.I read
+accesses as well as writes, and it will pinpoint the exact instruction that
+causes an error. It has been in use at Pixar since 1987, and at many other
+sites for years.
+.LP
+Electric Fence uses the virtual memory hardware of your computer to place an
+inaccessible memory page immediately after (or before, at the user's option)
+each memory allocation. When software reads or writes this inaccessible page,
+the
+hardware issues a segmentation fault, stopping the program at the offending
+instruction. It is then trivial to find the erroneous statement using your
+favorite debugger. In a similar manner, memory that has been released by
+free() is made inaccessible, and any code that touches it will get a
+segmentation fault.
+.LP
+Simply linking your application with libefence.a will allow you to detect
+most, but not all, malloc buffer overruns and accesses of free memory.
+If you want to be reasonably sure that you've found
+.I all
+bugs of this type, you'll have to read and understand the rest of this
+man page.
+.SH USAGE
+Link your program with the library
+.B libefence.a .
+Make sure you are
+.I not
+linking with
+.B -lmalloc,
+.B -lmallocdebug,
+or with other malloc-debugger or malloc-enhancer libraries.
+You can only use one at a time.
+If your system administrator
+has installed Electric Fence for public use, you'll be able to use the
+.B -lefence
+argument to the linker, otherwise you'll have to put the path-name for
+.B libefence.a
+in the linker's command line.
+Some systems will require special arguments to the linker to assure that
+you are using the Electric Fence malloc() and not the one from your C library.
+On AIX systems, you may have to use the flags
+.br
+.B -bnso
+.B -bnodelcsect
+.B -bI:/lib/syscalls.exp
+.br
+On Sun systems running SunOS 4.X, you'll probably have to use
+.B -Bstatic.
+.LP
+Run your program
+.I using a debugger. 
+It's easier to work this way than to create a
+.B core
+file and post-mortem debug it. Electric Fence can create
+.I huge
+core files, and some operating systems will thus take minutes simply to dump
+core! Some operating systems will not create usable core files from programs
+that are linked with Electric Fence.
+If your program has one of the errors detected by Electric Fence, it will
+get a segmentation fault (SIGSEGV) at the offending instruction. Use the
+debugger to locate the erroneous statement, and repair it.
+.SH GLOBAL AND ENVIRONMENT VARIABLES
+Electric Fence has six configuration switches that can be enabled via
+the shell environment, or by setting the value of global integer variables
+using a debugger. These switches change what bugs Electric Fence will detect,
+so it's important that you know how to use them.
+.TP
+EF_DISABLE_BANNER
+This is an integer which if nonzero specifies that the usual Electric
+Fence banner and copyright notice should not be printed.  This is
+provided for certain circumstances where the banner can be annoying
+(eg, running a regression test suite that also monitors stderr).  Note
+that you should almost certainly not set this in your program, because
+then you might leave Electric Fence linked into the production
+version, which would be very bad.
+.TP
+EF_ALIGNMENT
+This is an integer that specifies the alignment for any memory allocations
+that will be returned by malloc(), calloc(), and realloc().
+The value is specified in
+bytes, thus a value of 4 will cause memory to be aligned to 32-bit boundaries
+unless your system doesn't have a 8-bit characters. EF_ALIGNMENT is set to
+sizeof(int) by default, since that is generally the word-size of your CPU.
+If your program requires that allocations be aligned to 64-bit
+boundaries and you have a 32-bit
+.B int
+you'll have to set this value to 8. This is the case when compiling with the
+.B -mips2
+flag on MIPS-based systems such as those from SGI.
+The memory allocation that is returned by Electric Fence malloc() is aligned
+using the value in EF_ALIGNMENT, and
+.I its size the multiple of
+.I that value
+that is greater than or equal to the requested size.
+For this reason, you will sometimes want to set EF_ALIGNMENT to 0 (no
+alignment), so that
+you can detect overruns of less than your CPU's word size. Be sure to read
+the section
+.I WORD-ALIGNMENT AND OVERRUN DETECTION
+in this manual page before you try this.
+To change this value, set EF_ALIGNMENT in the shell environment to an
+integer value, or assign
+to the global integer variable EF_ALIGNMENT using a debugger.
+.TP
+EF_PROTECT_BELOW
+Electric Fence usually places an inaccessible page immediately after each
+memory allocation, so that software that runs past the end of the allocation
+will be detected. Setting EF_PROTECT_BELOW to 1 causes Electric Fence
+to place the inaccessible page
+.I before
+the allocation in the address space, so that under-runs will be detected
+instead of over-runs.
+When EF_PROTECT_BELOW is set, the EF_ALIGNMENT parameter is ignored.
+All allocations will be aligned to virtual-memory-page boundaries, and
+their size will be the exact size that was requested.
+To change this value, set EF_PROTECT_BELOW in the shell environment to an
+integer value, or assign to the global integer variable EF_PROTECT_BELOW using
+a debugger.
+.TP
+EF_PROTECT_FREE
+When EF_PROTECT_FREE is not set (i. e. set to 0), Electric Fence returns free
+memory to a pool and only checks accesses to it until it is reallocated. If
+you suspect that a program may be touching free memory, set EF_PROTECT_FREE to
+1. This will cause Electric Fence to never re-allocate memory once it has been
+freed, so that any access to free memory will be detected. Some programs will
+use tremendous amounts of memory when this parameter is set. To change this
+value, set EF_PROTECT_FREE in the shell environment to an integer value, or
+assign to the global integer variable EF_PROTECT_FREE using a debugger.
+.TP
+EF_ALLOW_MALLOC_0
+By default, Electric Fence traps calls to malloc() with a size of zero, because
+they are often the result of a software bug. If EF_ALLOW_MALLOC_0 is non-zero,
+the software will not trap calls to malloc() with a size of zero.
+To change this value, set EF_ALLOW_MALLOC_0 in the shell environment to an
+integer value, or assign to the global integer variable EF_ALLOW_MALLOC_0 using
+a debugger.
+.TP
+EF_FREE_WIPES
+By default, Electric Fence releases memory without changing the content
+of the released memory block.  IF EF_FREE_WIPES is non-zero, the sofware
+will fill the memory block with 0xbd values before it is released.
+This makes it easier to trigger illegal use of released memory, and eaiser
+to understand why a memory access failed during gdb runs.
+.SH WORD-ALIGNMENT AND OVERRUN DETECTION
+There is a conflict between the alignment restrictions that malloc() operates
+under and the debugging strategy used by Electric Fence. When detecting
+overruns, Electric Fence malloc() allocates two or more virtual memory
+pages for each allocation. The last page is made inaccessible in such a way
+that any read, write, or execute access will cause a segmentation fault.
+Then, Electric Fence malloc() will return an address such that the first
+byte after
+the end of the allocation is on the inaccessible page.
+Thus, any overrun
+of the allocation will cause a segmentation fault.
+.LP
+It follows that the
+address returned by malloc() is the address of the inaccessible page minus
+the size of the memory allocation.
+Unfortunately, malloc() is required to return
+.I word-aligned
+allocations, since many CPUs can only access a word when its address is aligned.
+The conflict happens when software makes a memory allocation using a size that
+is not a multiple of the word size, and expects to do word accesses to that
+allocation. The location of the inaccessible page is fixed by hardware at
+a word-aligned address. If Electric Fence malloc() is to return an aligned
+address, it must increase the size of the allocation to a multiple of the
+word size.
+In addition, the functions memalign() and valloc() must honor explicit
+specifications on the alignment of the memory allocation, and this, as well
+can only be implemented by increasing the size of the allocation.
+Thus, there will be situations in which the end of a memory allocation
+contains some padding space, and accesses of that padding space will not
+be detected, even if they are overruns.
+.LP
+Electric Fence provides the variable EF_ALIGNMENT so that the user can
+control the default alignment used by malloc(), calloc(), and realloc().
+To debug overruns as small as a single byte, you can set EF_ALIGNMENT to
+zero. This will result in Electric Fence malloc() returning unaligned
+addresses for allocations with sizes that are not a multiple of the word
+size. This is not a problem in most cases, because compilers must pad the
+size of objects so that alignment restrictions are honored when storing
+those objects in arrays. The problem surfaces when software allocates
+odd-sized buffers for objects that must be word-aligned. One case of this
+is software that allocates a buffer to contain a structure and a
+string, and the string has an odd size (this example was in a popular TIFF
+library). If word references are made to un-aligned buffers, you will see
+a bus error (SIGBUS) instead of a segmentation fault. The only way to fix
+this is to re-write the offending code to make byte references or not make
+odd-sized allocations, or to set EF_ALIGNMENT to the word size.
+.LP
+Another example of software incompatible with
+EF_ALIGNMENT < word-size
+is the strcmp() function and other string functions on SunOS (and probably
+Solaris), which make word-sized accesses to character strings, and may
+attempt to access up to three bytes beyond the end of a string. These
+result in a segmentation fault (SIGSEGV). The only way around this is to
+use versions of the string functions that perform byte references instead
+of word references.
+.SH INSTRUCTIONS FOR DEBUGGING YOUR PROGRAM
+.TP
+1.
+Link with libefence.a as explained above.
+.TP
+2.
+Run your program in a debugger and fix any overruns or accesses to free memory.
+.TP
+3.
+Quit the debugger.
+.TP
+4.
+Set EF_PROTECT_BELOW = 1 in the shell environment.
+.TP
+5.
+Repeat step 2, this time repairing underruns if they occur.
+.TP
+6.
+Quit the debugger.
+.TP
+7.
+Read the restrictions in the section on
+.I WORD-ALIGNMENT AND OVERRUN DETECTION.
+See if you can
+set EF_ALIGNMENT to 0 and repeat step 2. Sometimes this will be too much work,
+or there will be problems with library routines for which you don't have the
+source, that will prevent you from doing this.
+.SH MEMORY USAGE AND EXECUTION SPEED
+Since Electric Fence uses at least two virtual memory pages for each of its
+allocations, it's a terrible memory hog. I've sometimes found it necessary to
+add a swap file using swapon(8) so that the system would have enough virtual
+memory to debug my program. Also, the way we manipulate memory results in
+various cache and translation buffer entries being flushed with each call
+to malloc or free. The end result is that your program will be much slower
+and use more resources while you are debugging it with Electric Fence.
+.LP
+Don't leave libefence.a linked into production software! Use it only
+for debugging.
+.SH PORTING
+Electric Fence is written for ANSI C. You should be able to port it with
+simple changes to the Makefile and to page.c,
+which contains the memory management primitives .
+Many POSIX platforms will require only a re-compile.
+The operating system facilities required to port Electric Fence are:
+.IP
+A way to allocate memory pages
+.br
+A way to make selected pages inaccessible.
+.br
+A way to make the pages accessible again.
+.br
+A way to detect when a program touches an inaccessible page.
+.br
+A way to print messages.
+.LP
+Please e-mail me a copy of any changes you have to make, so that I can
+merge them into the distribution.
+.SH AUTHOR
+Bruce Perens
+.SH WARNINGS
+I have tried to do as good a job as I can on this software, but I doubt
+that it is even theoretically possible to make it bug-free.
+This software has no warranty. It will not detect some bugs that you might
+expect it to detect, and will indicate that some non-bugs are bugs.
+Bruce Perens and/or Pixar will not be liable to any claims resulting
+from the use of this software or the ideas within it.
+The entire responsibility for its use must
+be assumed by the user. If you use it and it results in loss of life
+and/or property, tough. If it leads you on a wild goose chase and you waste
+two weeks debugging something, too bad.
+If you can't deal with the above, please don't use the software! I've written
+this in an attempt to help other people, not to get myself sued or prosecuted.
+.SH LICENSE
+Copyright 1987-1995 Bruce Perens. All rights reserved.
+.br
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License, Version 2,
+as published by the Free Software Foundation. A copy of this license is
+distributed with this software in the file "COPYING".
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Read the
+file "COPYING" for more details.
+.SH CONTACTING THE AUTHOR
+.nf
+Bruce Perens
+c/o Pixar
+1001 West Cutting Blvd., Suite 200
+Richmond, CA 94804
+
+Telephone: 510-215-3502
+Fax: 510-236-0388
+Internet: Bruce@Pixar.com
+.fi
+.ft
+.SH FILES
+/dev/zero: Source of memory pages (via mmap(2)).
+.SH SEE ALSO
+malloc(3), mmap(2), mprotect(2), swapon(8)
+.SH DIAGNOSTICS
+Segmentation Fault: Examine the offending statement for violation of the
+boundaries of a memory allocation.
+.br
+Bus Error: See the section on
+.I WORD-ALIGNMENT AND OVERRUN DETECTION.
+in this manual page.
+.SH BUGS
+My explanation of the alignment issue could be improved.
+.LP
+Some Sun systems running SunOS 4.1 are reported to signal an access to a
+protected page with
+.B  SIGBUS
+rather than
+.B SIGSEGV,
+I suspect this is an undocumented feature of a particular Sun hardware
+version, not just the operating system.
+On these systems, eftest will fail with a bus error until you modify the
+Makefile to define
+.B PAGE_PROTECTION_VIOLATED_SIGNAL
+as
+.B SIGBUS.
+.LP
+There are, without doubt, other bugs and porting issues. Please contact me via
+e-mail if you have any bug reports, ideas, etc.
+.SH WHAT'S BETTER
+PURIFY, from Purify Systems, does a much better job than Electric Fence, and
+does much more. It's available at this writing on SPARC and HP.
+I'm not affiliated with Purify, I just think it's a wonderful product
+and you should check it out.
diff --git a/user/electric-fence/page.c b/user/electric-fence/page.c
new file mode 100644 (file)
index 0000000..925c44c
--- /dev/null
@@ -0,0 +1,188 @@
+/* For email below, drop spaces and <spam-buster> tag.
+ * MODIFIED:  March 20, 2014 (jric<spam-buster> @ <spam-buster> chegg DOT com)
+*/
+#include "efence.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+
+/*
+ * Lots of systems are missing the definition of PROT_NONE.
+ */
+#ifndef        PROT_NONE
+#define        PROT_NONE       0
+#endif
+
+/*
+ * 386 BSD has MAP_ANON instead of MAP_ANONYMOUS.
+ */
+#if ( !defined(MAP_ANONYMOUS) && defined(MAP_ANON) )
+#define        MAP_ANONYMOUS   MAP_ANON
+#endif
+
+/*
+ * For some reason, I can't find mprotect() in any of the headers on
+ * IRIX or SunOS 4.1.2
+ */
+/* extern C_LINKAGE int mprotect(void * addr, size_t len, int prot); */
+
+static caddr_t startAddr = (caddr_t) 0;
+
+#if ( !defined(sgi) && !defined(_AIX) && __DARWIN_C_LEVEL < __DARWIN_C_FULL )
+extern int     sys_nerr;
+/*extern char *        sys_errlist[];*/
+#endif
+
+static const char *
+stringErrorReport(void)
+{
+#if ( defined(sgi) )
+       return strerror(oserror());
+#elif ( defined(_AIX) )
+       return strerror(errno);
+#else
+       if ( errno > 0 && errno < sys_nerr )
+               return sys_errlist[errno];
+       else
+               return "Unknown error.\n";
+#endif
+}
+
+/*
+ * Create memory.
+ */
+#if defined(MAP_ANONYMOUS)
+void *
+Page_Create(size_t size)
+{
+       caddr_t         allocation;
+
+       /*
+        * In this version, "startAddr" is a _hint_, not a demand.
+        * When the memory I map here is contiguous with other
+        * mappings, the allocator can coalesce the memory from two
+        * or more mappings into one large contiguous chunk, and thus
+        * might be able to find a fit that would not otherwise have
+        * been possible. I could _force_ it to be contiguous by using
+        * the MMAP_FIXED flag, but I don't want to stomp on memory mappings
+        * generated by other software, etc.
+        */
+       allocation = (caddr_t) mmap(
+        startAddr
+       ,size
+       ,PROT_READ|PROT_WRITE
+       ,MAP_PRIVATE|MAP_ANONYMOUS
+       ,-1
+       ,0);
+
+#ifndef        __hpux
+       /*
+        * Set the "address hint" for the next mmap() so that it will abut
+        * the mapping we just created.
+        *
+        * HP/UX 9.01 has a kernel bug that makes mmap() fail sometimes
+        * when given a non-zero address hint, so we'll leave the hint set
+        * to zero on that system. HP recently told me this is now fixed.
+        * Someone please tell me when it is probable to assume that most
+        * of those systems that were running 9.01 have been upgraded.
+        */
+       startAddr = allocation + size;
+#endif
+
+       if ( allocation == (caddr_t)-1 )
+               EF_Exit("mmap() failed: %s", stringErrorReport());
+
+       return (void *)allocation;
+}
+#else
+void *
+Page_Create(size_t size)
+{
+       static int      devZeroFd = -1;
+       caddr_t         allocation;
+
+       if ( devZeroFd == -1 ) {
+               devZeroFd = open("/dev/zero", O_RDWR);
+               if ( devZeroFd < 0 )
+                       EF_Exit(
+                        "open() on /dev/zero failed: %s"
+                       ,stringErrorReport());
+       }
+
+       /*
+        * In this version, "startAddr" is a _hint_, not a demand.
+        * When the memory I map here is contiguous with other
+        * mappings, the allocator can coalesce the memory from two
+        * or more mappings into one large contiguous chunk, and thus
+        * might be able to find a fit that would not otherwise have
+        * been possible. I could _force_ it to be contiguous by using
+        * the MMAP_FIXED flag, but I don't want to stomp on memory mappings
+        * generated by other software, etc.
+        */
+       allocation = (caddr_t) mmap(
+        startAddr
+       ,size
+       ,PROT_READ|PROT_WRITE
+       ,MAP_PRIVATE
+       ,devZeroFd
+       ,0);
+
+       startAddr = allocation + size;
+
+       if ( allocation == (caddr_t)-1 )
+               EF_Exit("mmap() failed: %s", stringErrorReport());
+
+       return (void *)allocation;
+}
+#endif
+
+static void
+mprotectFailed(void)
+{
+       EF_Exit("mprotect() failed: %s", stringErrorReport());
+}
+
+void
+Page_AllowAccess(void * address, size_t size)
+{
+       if ( mprotect((caddr_t)address, size, PROT_READ|PROT_WRITE) < 0 )
+               mprotectFailed();
+}
+
+void
+Page_DenyAccess(void * address, size_t size)
+{
+       if ( mprotect((caddr_t)address, size, PROT_NONE) < 0 )
+               mprotectFailed();
+}
+
+void
+Page_Delete(void * address, size_t size)
+{
+       Page_DenyAccess(address, size);
+}
+
+#if defined(_SC_PAGESIZE)
+size_t
+Page_Size(void)
+{
+       return (size_t)sysconf(_SC_PAGESIZE);
+}
+#elif defined(_SC_PAGE_SIZE)
+size_t
+Page_Size(void)
+{
+       return (size_t)sysconf(_SC_PAGE_SIZE);
+}
+#else
+/* extern int  getpagesize(); */
+size_t
+Page_Size(void)
+{
+       return getpagesize();
+}
+#endif
diff --git a/user/electric-fence/print.c b/user/electric-fence/print.c
new file mode 100644 (file)
index 0000000..c28189e
--- /dev/null
@@ -0,0 +1,170 @@
+#include "efence.h"
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <string.h>
+#include <signal.h>
+
+/*
+ * These routines do their printing without using stdio. Stdio can't
+ * be used because it calls malloc(). Internal routines of a malloc()
+ * debugger should not re-enter malloc(), so stdio is out.
+ */
+
+/*
+ * NUMBER_BUFFER_SIZE is the longest character string that could be needed
+ * to represent an unsigned integer, assuming we might print in base 2.
+ */
+#define        NUMBER_BUFFER_SIZE      (sizeof(ef_number) * NBBY)
+
+static void
+printNumber(ef_number number, ef_number base)
+{
+       char            buffer[NUMBER_BUFFER_SIZE];
+       char *          s = &buffer[NUMBER_BUFFER_SIZE];
+       int             size;
+       
+       do {
+               ef_number       digit;
+
+               if ( --s == buffer )
+                       EF_Abort("Internal error printing number.");
+
+               digit = number % base;
+
+               if ( digit < 10 )
+                       *s = '0' + digit;
+               else
+                       *s = 'a' + digit - 10;
+
+       } while ( (number /= base) > 0 );
+
+       size = &buffer[NUMBER_BUFFER_SIZE] - s;
+
+       if ( size > 0 )
+               write(2, s, size);
+}
+
+static void
+vprint(const char * pattern, va_list args)
+{
+       static const char       bad_pattern[] =
+        "\nBad pattern specifier %%%c in EF_Print().\n";
+       const char *    s = pattern;
+       char            c;
+
+       while ( (c = *s++) != '\0' ) {
+               if ( c == '%' ) {
+                       c = *s++;
+                       switch ( c ) {
+                       case '%':
+                               (void) write(2, &c, 1);
+                               break;
+                       case 'a':
+                               /*
+                                * Print an address passed as a void pointer.
+                                * The type of ef_number must be set so that
+                                * it is large enough to contain all of the
+                                * bits of a void pointer.
+                                */
+                               printNumber(
+                                (ef_number)va_arg(args, void *)
+                               ,0x10);
+                               break;
+                       case 's':
+                               {
+                                       const char *    string;
+                                       size_t          length;
+
+                                       string = va_arg(args, char *);
+                                       length = strlen(string);
+
+                                       (void) write(2, string, length);
+                               }
+                               break;
+                       case 'd':
+                               {
+                                       int     n = va_arg(args, int);
+
+                                       if ( n < 0 ) {
+                                               char    c = '-';
+                                               write(2, &c, 1);
+                                               n = -n;
+                                       }
+                                       printNumber(n, 10);
+                               }
+                               break;
+                       case 'x':
+                               printNumber(va_arg(args, u_int), 0x10);
+                               break;
+                       case 'c':
+                               { /*Cast used, since char gets promoted to int in ... */
+                                       char    c = (char) va_arg(args, int);
+                                       
+                                       (void) write(2, &c, 1);
+                               }
+                               break;
+                       default:
+                               {
+                                       EF_Print(bad_pattern, c);
+                               }
+               
+                       }
+               }
+               else
+                       (void) write(2, &c, 1);
+       }
+}
+
+void
+EF_Abort(const char * pattern, ...)
+{
+       va_list args;
+
+       va_start(args, pattern);
+
+       EF_Print("\nElectricFence Aborting: ");
+       vprint(pattern, args);
+       EF_Print("\n");
+
+       va_end(args);
+
+       /*
+        * I use kill(getpid(), SIGILL) instead of abort() because some
+        * mis-guided implementations of abort() flush stdio, which can
+        * cause malloc() or free() to be called.
+        */
+       kill(getpid(), SIGILL);
+       /* Just in case something handles SIGILL and returns, exit here. */
+       _exit(-1);
+}
+
+void
+EF_Exit(const char * pattern, ...)
+{
+       va_list args;
+
+       va_start(args, pattern);
+
+       EF_Print("\nElectricFence Exiting: ");
+       vprint(pattern, args);
+       EF_Print("\n");
+
+       va_end(args);
+
+       /*
+        * I use _exit() because the regular exit() flushes stdio,
+        * which may cause malloc() or free() to be called.
+        */
+       _exit(-1);
+}
+
+void
+EF_Print(const char * pattern, ...)
+{
+       va_list args;
+
+       va_start(args, pattern);
+       vprint(pattern, args);
+       va_end(args);
+}
diff --git a/user/electric-fence/tstheap.c b/user/electric-fence/tstheap.c
new file mode 100644 (file)
index 0000000..c712fed
--- /dev/null
@@ -0,0 +1,61 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <limits.h>
+#include "efence.h"
+
+/*
+ * This is a simple program to exercise the allocator. It allocates and frees
+ * memory in a pseudo-random fashion. It should run silently, using up time
+ * and resources on your system until you stop it or until it has gone
+ * through TEST_DURATION (or the argument) iterations of the loop.
+ */
+
+extern C_LINKAGE double drand48(void); /* For pre-ANSI C systems */
+
+#define        POOL_SIZE       1024
+#define        LARGEST_BUFFER  30000
+#define        TEST_DURATION   1000000
+
+void * pool[POOL_SIZE];
+
+#ifdef FAKE_DRAND48
+/*
+ * Add -DFAKE_DRAND48 to your compile flags if your system doesn't
+ * provide drand48().
+ */
+
+#ifndef        ULONG_MAX
+#define        ULONG_MAX       ~(1L)
+#endif
+
+double
+drand48(void)
+{
+       return (random() / (double)ULONG_MAX);
+}
+#endif
+
+int
+main(int argc, char * * argv)
+{
+       int     count = 0;
+       int     duration = TEST_DURATION;
+
+       if ( argc >= 2 )
+               duration = atoi(argv[1]);
+
+       for ( ; count < duration; count++ ) {
+               void * *        element = &pool[(int)(drand48() * POOL_SIZE)];
+               size_t          size = (size_t)(drand48() * (LARGEST_BUFFER + 1));
+
+               if ( *element ) {
+                       free( *element );
+                       *element = 0;
+               }
+               else if ( size > 0 ) {
+                       *element = malloc(size);
+               }
+       }
+       return 0;
+}