From: Harlan Stenn Date: Thu, 13 Jul 2000 21:57:59 +0000 (-0000) Subject: Many files: X-Git-Tag: NTP_4_0_99_K~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5afb2974cc0501bbdc074a8e69e40e108d3ab824;p=thirdparty%2Fntp.git Many files: * configure.in (AC_CONFIG_FILES): Added ElectricFence/Makefile * ElectricFence: Imporpted. bk: 396e3b67GkAAj1vXuk5j5HkiUAxfpA --- diff --git a/ChangeLog b/ChangeLog index b180b7fe4e..068a7a0be3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,46 @@ +2000-07-13 Harlan Stenn + + * configure.in (AC_CONFIG_FILES): Added ElectricFence/Makefile + * ElectricFence: Imporpted. + +2000-07-12 Harlan Stenn + + * util/ntp_genkeys.c (main): Cleanup + * ntpd/refclock_wwv.c (wwv_qrz): sqrt -> SQRT + * ntpd/refclock_chu.c (chu_rf): sqrt -> SQRT + * ntpd/ntpd.c (set_process_priority): Disable high-priority for now. + PUBKEY cleanup. + * ntpd/ntp_timer.c: sys_revoketime cleanup. + * ntpd/ntp_proto.c (receive): PUBKEY cleanup. Comment and code + cleanup. + (process_packet): Comment and code (PUBKEY) cleanup. + (peer_xmit): Comment and code cleanup. + (fast_xmit): Comment and code cleanup. + * ntpd/ntp_peer.c (expire_all): revoketime cleanup. PUBKEY cleanup. + * ntpd/ntp_crypto.c: Comment reorg. DH parameters are now + file-static instead of local to subroutines. + (make_keylist): peer->pcookie.key cleanup/fix + (crypto_recv): Subroutine documentation cleanup, other cleanup + (crypto_xmit): Cleanup/document. + (crypto_setup): Cleanup/document. + (crypto_agree): Cleanup/document. + (crypto_rsa): now static + (crypto_dh): now static. Comment cleanup. Code cleanup. + (crypto_tai): now static. Code and comment cleanup. + (crypto_config): Deal with CRYPTO_CONF_LEAP. + * ntpd/ntp_control.c (CS_DHPARAMS): Rename corresponding token to + "params". Remove CS_TAI from def_sys_var[]. + (ctl_putsys): CS_HOST, CS_DHPARAMSm CS_REVTIME, and CS_LEAPTIME + bugfix. CS_TAI cleanup. + * ntpd/ntp_config.c (CONF_CRYPTO_LEAP): Added + (getconfig): Added CONF_CRYPTO_LEAP support. + * include/ntp_syslog.h: Lose GIZMO stuff. + * include/ntp_crypto.h (CRYPTO_CONF_LEAP): Added + * include/ntp.h: struct autokey, cookie,value, and pkt changes for + signature field. Update the inline docs on pkt's exten field. + From: Dave Mills + + 2000-07-08 Harlan Stenn * ntpd/ntp_util.c (stats_config): If we read a bogus old_drift, diff --git a/ElectricFence/CHANGES b/ElectricFence/CHANGES new file mode 100644 index 0000000000..454aff6d3b --- /dev/null +++ b/ElectricFence/CHANGES @@ -0,0 +1,23 @@ +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/ElectricFence/COPYING b/ElectricFence/COPYING new file mode 100644 index 0000000000..a43ea2126f --- /dev/null +++ b/ElectricFence/COPYING @@ -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. + + 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.) + +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. + + 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. + + 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 + + Appendix: 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. + + + Copyright (C) 19yy + + 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. + + , 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/ElectricFence/Makefile- b/ElectricFence/Makefile- new file mode 100644 index 0000000000..0ce8c050dd --- /dev/null +++ b/ElectricFence/Makefile- @@ -0,0 +1,72 @@ +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 + +PACKAGE_SOURCE= README libefence.3 Makefile efence.h \ + efence.c page.c print.c eftest.c tstheap.c CHANGES + +# 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 + +eftest: libefence.a eftest.o + - rm -f eftest + $(CC) $(CFLAGS) eftest.o libefence.a -o eftest + +$(OBJECTS) tstheap.o eftest.o: efence.h diff --git a/ElectricFence/Makefile.am b/ElectricFence/Makefile.am new file mode 100644 index 0000000000..8b3c9613b5 --- /dev/null +++ b/ElectricFence/Makefile.am @@ -0,0 +1,29 @@ +# Harlan Stenn +# Converted the original Makefile (now in Makefile-) to Makefile.am +# in July of '00 + +EXTRA_DIST = libefence.3 CHANGES +libefence_a_SOURCES = efence.h efence.c page.c print.c +check_PROGRAMS = eftest tstheap +# TESTS = eftest tstheap +noinst_LIBRARIES = libefence.a +LDADD = libefence.a + +# 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 + +check-local: + ./eftest + ./tstheap 3072 diff --git a/ElectricFence/Makefile.in b/ElectricFence/Makefile.in new file mode 100644 index 0000000000..8ae4c498c7 --- /dev/null +++ b/ElectricFence/Makefile.in @@ -0,0 +1,376 @@ +# Makefile.in generated automatically by automake 1.4a from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_FLAG = +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : + +@SET_MAKE@ +build_alias = @build_alias@ +build_triplet = @build@ +host_alias = @host_alias@ +host_triplet = @host@ +target_alias = @target_alias@ +target_triplet = @target@ +AMDEP = @AMDEP@ +AMTAR = @AMTAR@ +AUTOKEY = @AUTOKEY@ +AWK = @AWK@ +CC = @CC@ +CFLAGS = @CFLAGS@ +CHUTEST = @CHUTEST@ +CLKTEST = @CLKTEST@ +CPP = @CPP@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +DCFD = @DCFD@ +DEPDIR = @DEPDIR@ +LDFLAGS = @LDFLAGS@ +LIBPARSE = @LIBPARSE@ +LIBRSAREF = @LIBRSAREF@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +MAKE_ADJTIMED = @MAKE_ADJTIMED@ +MAKE_CHECK_Y2K = @MAKE_CHECK_Y2K@ +MAKE_LIBPARSE = @MAKE_LIBPARSE@ +MAKE_LIBPARSE_KERNEL = @MAKE_LIBPARSE_KERNEL@ +MAKE_LIBRSAREF = @MAKE_LIBRSAREF@ +MAKE_NTPTIME = @MAKE_NTPTIME@ +MAKE_NTP_GENKEYS = @MAKE_NTP_GENKEYS@ +MAKE_PARSEKMODULE = @MAKE_PARSEKMODULE@ +MAKE_TICKADJ = @MAKE_TICKADJ@ +PACKAGE = @PACKAGE@ +PATH_PERL = @PATH_PERL@ +PATH_SH = @PATH_SH@ +PROPDELAY = @PROPDELAY@ +RANLIB = @RANLIB@ +RSAREF = @RSAREF@ +TESTDCF = @TESTDCF@ +U = @U@ +VERSION = @VERSION@ +install_sh = @install_sh@ + + +EXTRA_DIST = libefence.3 CHANGES +libefence_a_SOURCES = efence.h efence.c page.c print.c +check_PROGRAMS = eftest tstheap +# TESTS = eftest tstheap +noinst_LIBRARIES = libefence.a +LDADD = libefence.a +subdir = ElectricFence +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LIBRARIES = $(noinst_LIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LIBS = @LIBS@ +libefence_a_AR = $(AR) cru +libefence_a_LIBADD = +am_libefence_a_OBJECTS = efence.o page.o print.o +libefence_a_OBJECTS = $(am_libefence_a_OBJECTS) +AR = ar +eftest_SOURCES = eftest.c +eftest_OBJECTS = eftest.o +eftest_LDADD = $(LDADD) +eftest_DEPENDENCIES = libefence.a +eftest_LDFLAGS = +tstheap_SOURCES = tstheap.c +tstheap_OBJECTS = tstheap.o +tstheap_LDADD = $(LDADD) +tstheap_DEPENDENCIES = libefence.a +tstheap_LDFLAGS = +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +DIST_SOURCES = $(libefence_a_SOURCES) eftest.c tstheap.c +DIST_COMMON = README COPYING Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) + +GZIP_ENV = --best +depcomp = $(SHELL) $(top_srcdir)/depcomp +DEP_FILES = @AMDEP@ $(DEPDIR)/efence.Po $(DEPDIR)/eftest.Po \ +$(DEPDIR)/page.Po $(DEPDIR)/print.Po $(DEPDIR)/tstheap.Po +SOURCES = $(libefence_a_SOURCES) eftest.c tstheap.c +OBJECTS = $(am_libefence_a_OBJECTS) eftest.o tstheap.o + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .c .h .o +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu ElectricFence/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status $(BUILT_SOURCES) + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-noinstLIBRARIES: + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +distclean-noinstLIBRARIES: + +maintainer-clean-noinstLIBRARIES: + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +libefence.a: $(libefence_a_OBJECTS) $(libefence_a_DEPENDENCIES) + -rm -f libefence.a + $(libefence_a_AR) libefence.a $(libefence_a_OBJECTS) $(libefence_a_LIBADD) + $(RANLIB) libefence.a + +mostlyclean-checkPROGRAMS: + +clean-checkPROGRAMS: + -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) + +distclean-checkPROGRAMS: + +maintainer-clean-checkPROGRAMS: + +eftest: $(eftest_OBJECTS) $(eftest_DEPENDENCIES) + @rm -f eftest + $(LINK) $(eftest_LDFLAGS) $(eftest_OBJECTS) $(eftest_LDADD) $(LIBS) + +tstheap: $(tstheap_OBJECTS) $(tstheap_DEPENDENCIES) + @rm -f tstheap + $(LINK) $(tstheap_LDFLAGS) $(tstheap_OBJECTS) $(tstheap_LDADD) $(LIBS) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + mkid -fID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || etags $(ETAGS_ARGS) $$tags $$unique $(LISP) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pR $$d/$$file $(distdir); \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +@AMDEP@include $(DEPDIR)/efence.Po +@AMDEP@include $(DEPDIR)/eftest.Po +@AMDEP@include $(DEPDIR)/page.Po +@AMDEP@include $(DEPDIR)/print.Po +@AMDEP@include $(DEPDIR)/tstheap.Po + +mostlyclean-depend: + +clean-depend: + +distclean-depend: + -rm -rf $(DEPDIR) + +maintainer-clean-depend: + +@AMDEP@CCDEPMODE = @CCDEPMODE@ + +.c.o: +@AMDEP@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@ +@AMDEP@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + $(COMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$< + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-local +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: +uninstall: uninstall-am +all-am: Makefile $(LIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_STRIP_FLAG=-s install +installdirs: + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: + -rm -f Makefile.in +mostlyclean-am: mostlyclean-noinstLIBRARIES mostlyclean-compile \ + mostlyclean-checkPROGRAMS mostlyclean-tags \ + mostlyclean-depend mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-noinstLIBRARIES clean-compile clean-checkPROGRAMS \ + clean-tags clean-depend clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-noinstLIBRARIES distclean-compile \ + distclean-checkPROGRAMS distclean-tags distclean-depend \ + distclean-generic clean-am + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-noinstLIBRARIES \ + maintainer-clean-compile maintainer-clean-checkPROGRAMS \ + maintainer-clean-tags maintainer-clean-depend \ + maintainer-clean-generic distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-noinstLIBRARIES distclean-noinstLIBRARIES \ +clean-noinstLIBRARIES maintainer-clean-noinstLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-checkPROGRAMS \ +distclean-checkPROGRAMS clean-checkPROGRAMS \ +maintainer-clean-checkPROGRAMS tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir mostlyclean-depend \ +distclean-depend clean-depend maintainer-clean-depend info-am info \ +dvi-am dvi check-local check check-am installcheck-am installcheck \ +install-exec-am install-exec install-data-am install-data install-am \ +install uninstall-am uninstall all-redirect all-am all install-strip \ +installdirs mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# 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 + +check-local: + ./eftest + ./tstheap 3072 + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/ElectricFence/README b/ElectricFence/README new file mode 100644 index 0000000000..8223850fa4 --- /dev/null +++ b/ElectricFence/README @@ -0,0 +1,46 @@ +This is Electric Fence 2.0.5 + +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: + 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. + +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 . + + Thanks + + Bruce Perens + Bruce@Pixar.com diff --git a/ElectricFence/efence.c b/ElectricFence/efence.c new file mode 100644 index 0000000000..f797e75ffc --- /dev/null +++ b/ElectricFence/efence.c @@ -0,0 +1,786 @@ +/* + * Electric Fence - Red-Zone memory allocator. + * Bruce Perens, 1988, 1993 + * + * 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 +#include +#include +#include + +#ifdef malloc +#undef malloc +#endif + +#ifdef calloc +#undef calloc +#endif + +static const char version[] = "\n Electric Fence 2.0.5" + " Copyright (C) 1987-1995 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_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; + +/* + * 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; + +/* + * 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; + + 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; + } + + /* + * 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. */ + if ( EF_PROTECT_FREE ) + Page_Delete(address, bytesPerPage); + else + 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. */ + if ( EF_PROTECT_FREE ) + Page_Delete(address, bytesPerPage); + else + 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; + + if ( address == 0 ) + 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; + + 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. + * + * Some operating systems allow munmap() with single-page resolution, + * and allow you to un-map portions of a region, rather than the + * entire region that was mapped with mmap(). On those operating + * systems, we can release protected free pages with Page_Delete(), + * in the hope that the swap space attached to those pages will be + * released as well. + */ + if ( EF_PROTECT_FREE ) + Page_Delete(slot->internalAddress, slot->internalSize); + else + Page_DenyAccess(slot->internalAddress, slot->internalSize); + + if ( !noAllocationListProtection ) + Page_DenyAccess(allocationList, allocationListSize); +} + +extern C_LINKAGE void * +realloc(void * oldBuffer, size_t newSize) +{ + void * newBuffer = malloc(newSize); + + 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() */ + } + + return newBuffer; +} + +extern C_LINKAGE void * +malloc(size_t size) +{ + if ( allocationList == 0 ) + initialize(); /* This sets EF_ALIGNMENT */ + + return memalign(EF_ALIGNMENT, size); +} + +extern C_LINKAGE void * +calloc(size_t nelem, size_t elsize) +{ + size_t size = nelem * elsize; + void * allocation = malloc(size); + + memset(allocation, 0, size); + 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) +{ + return memalign(bytesPerPage, size); +} + +#ifdef __hpux +/* + * HP-UX 8/9.01 strcat reads a word past source when doing unaligned copies! + * Work around it here. The bug report has been filed with HP. + */ +char *strcat(char *d, const char *s) +{ + strcpy(d+strlen(d), s); + return d; +} +#endif diff --git a/ElectricFence/efence.h b/ElectricFence/efence.h new file mode 100644 index 0000000000..60eb30ff0a --- /dev/null +++ b/ElectricFence/efence.h @@ -0,0 +1,42 @@ +#include +#include + +/* + * 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 + * . + */ +#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/ElectricFence/eftest.c b/ElectricFence/eftest.c new file mode 100644 index 0000000000..03489d0896 --- /dev/null +++ b/ElectricFence/eftest.c @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#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 jmp_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); + longjmp(env, 1); +} + +static int +gotSegmentationFault(int (*test)(void)) +{ + if ( setjmp(env) == 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/ElectricFence/libefence.3 b/ElectricFence/libefence.3 new file mode 100644 index 0000000000..34fd25c5b2 --- /dev/null +++ b/ElectricFence/libefence.3 @@ -0,0 +1,382 @@ +.TH efence 3 27-April-1993 +.SH NAME +efence \- Electric Fence Malloc Debugger +.SH SYNOPSIS +.nf +.ft B +#include +.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_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 +.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 four 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_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 +Electric Fence usually returns free memory to a pool from which it may be +re-allocated. 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_ALLOC_MALLOC_0 in the shell environment to an +integer value, or assign to the global integer variable EF_ALLOC_MALLOC_0 using +a debugger. +.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/ElectricFence/page.c b/ElectricFence/page.c new file mode 100644 index 0000000000..135188743f --- /dev/null +++ b/ElectricFence/page.c @@ -0,0 +1,186 @@ +#include "efence.h" +#include +#include +#include +#include +#include +#include +#include + +/* + * 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) ) +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 + ,(int)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 + ,(int)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) +{ + if ( munmap((caddr_t)address, size) < 0 ) + 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/ElectricFence/print.c b/ElectricFence/print.c new file mode 100644 index 0000000000..f32ed2b290 --- /dev/null +++ b/ElectricFence/print.c @@ -0,0 +1,170 @@ +#include "efence.h" +#include +#include +#include +#include +#include + +/* + * 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': + { + char c = va_arg(args, char); + + (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/ElectricFence/tstheap.c b/ElectricFence/tstheap.c new file mode 100644 index 0000000000..c712fed5a4 --- /dev/null +++ b/ElectricFence/tstheap.c @@ -0,0 +1,61 @@ +#include +#include +#include +#include +#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; +} diff --git a/configure b/configure index 580a9ca7af..807b7935cc 100755 --- a/configure +++ b/configure @@ -11126,13 +11126,13 @@ cat >$CONFIG_STATUS <