From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-0.0 required=5.0 tests=T_SCC_BODY_TEXT_LINE, UNPARSEABLE_RELAY autolearn=ham autolearn_force=no version=3.4.4 Received: (qmail 11209 invoked from network); 14 Apr 2022 16:44:18 -0000 Received: from bsd.lv (HELO mandoc.bsd.lv) (66.111.2.12) by inbox.vuxu.org with ESMTPUTF8; 14 Apr 2022 16:44:18 -0000 Received: from fantadrom.bsd.lv (localhost [127.0.0.1]) by mandoc.bsd.lv (OpenSMTPD) with ESMTP id 72dd67a9 for ; Thu, 14 Apr 2022 11:44:16 -0500 (EST) Received: from localhost (mandoc.bsd.lv [local]) by mandoc.bsd.lv (OpenSMTPD) with ESMTPA id f4a33e57 for ; Thu, 14 Apr 2022 11:44:15 -0500 (EST) Date: Thu, 14 Apr 2022 11:44:15 -0500 (EST) X-Mailinglist: mandoc-source Reply-To: source@mandoc.bsd.lv MIME-Version: 1.0 From: schwarze@mandoc.bsd.lv To: source@mandoc.bsd.lv Subject: mandoc: support for hunting memory leaks; designed and written last X-Mailer: activitymail 1.26, http://search.cpan.org/dist/activitymail/ Content-Type: text/plain; charset=utf-8 Message-ID: <33650740a75e9d72@mandoc.bsd.lv> Log Message: ----------- support for hunting memory leaks; designed and written last autumn, polished today Modified Files: -------------- mandoc: Makefile Makefile.depend configure configure.local.example demandoc.c main.c man_macro.c mandoc_aux.c mandoc_aux.h mandoc_headers.3 mandocd.c mandocdb.c mdoc_macro.c mdoc_state.c tbl_html.c tbl_term.c Added Files: ----------- mandoc: mandoc_dbg.c mandoc_dbg.h mandoc_dbg_init.3 Revision Data ------------- Index: Makefile.depend =================================================================== RCS file: /home/cvs/mandoc/mandoc/Makefile.depend,v retrieving revision 1.51 retrieving revision 1.52 diff -LMakefile.depend -LMakefile.depend -u -p -r1.51 -r1.52 --- Makefile.depend +++ Makefile.depend @@ -1,8 +1,8 @@ arch.o: arch.c config.h roff.h att.o: att.c config.h roff.h libmdoc.h catman.o: catman.c config.h compat_fts.h -cgi.o: cgi.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h mansearch.h cgi.h -chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_ohash.h compat_ohash.h libmandoc.h +cgi.o: cgi.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h mansearch.h cgi.h +chars.o: chars.c config.h mandoc.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h libmandoc.h compat_err.o: compat_err.c config.h compat_fts.o: compat_fts.c config.h compat_fts.h compat_getline.o: compat_getline.c config.h @@ -22,62 +22,63 @@ compat_strndup.o: compat_strndup.c confi compat_strsep.o: compat_strsep.c config.h compat_strtonum.o: compat_strtonum.c config.h compat_vasprintf.o: compat_vasprintf.c config.h -dba.o: dba.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mansearch.h dba_write.h dba_array.h dba.h -dba_array.o: dba_array.c config.h mandoc_aux.h dba_write.h dba_array.h -dba_read.o: dba_read.c config.h mandoc_aux.h mansearch.h dba_array.h dba.h dbm.h +dba.o: dba.c config.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h mansearch.h dba_write.h dba_array.h dba.h +dba_array.o: dba_array.c config.h mandoc_aux.h mandoc_dbg.h dba_write.h dba_array.h +dba_read.o: dba_read.c config.h mandoc_aux.h mandoc_dbg.h mansearch.h dba_array.h dba.h dbm.h dba_write.o: dba_write.c config.h dba_write.h dbm.o: dbm.c config.h mansearch.h dbm_map.h dbm.h dbm_map.o: dbm_map.c config.h mansearch.h dbm_map.h dbm.h -demandoc.o: demandoc.c config.h mandoc.h roff.h man.h mdoc.h mandoc_parse.h -eqn.o: eqn.c config.h mandoc_aux.h mandoc.h roff.h eqn.h libmandoc.h eqn_parse.h +demandoc.o: demandoc.c config.h mandoc.h mandoc_dbg.h roff.h man.h mdoc.h mandoc_parse.h +eqn.o: eqn.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h eqn.h libmandoc.h eqn_parse.h eqn_html.o: eqn_html.c config.h mandoc.h roff.h eqn.h out.h html.h eqn_term.o: eqn_term.c config.h eqn.h out.h term.h -html.o: html.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h +html.o: html.c config.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h out.h html.h manconf.h main.h lib.o: lib.c config.h roff.h libmdoc.h lib.in -main.o: main.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h tag.h term_tag.h main.h manconf.h mansearch.h -man.o: man.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -man_html.o: man_html.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h html.h main.h -man_macro.o: man_macro.c config.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h -man_term.o: man_term.c config.h mandoc_aux.h mandoc.h roff.h man.h out.h term.h term_tag.h main.h -man_validate.o: man_validate.c config.h mandoc_aux.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h tag.h -mandoc.o: mandoc.c config.h mandoc_aux.h mandoc.h roff.h libmandoc.h roff_int.h -mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h +main.o: main.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h mandoc_xr.h roff.h mdoc.h man.h mandoc_parse.h tag.h term_tag.h main.h manconf.h mansearch.h +man.o: man.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +man_html.o: man_html.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h man.h out.h html.h main.h +man_macro.o: man_macro.c config.h mandoc_dbg.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h +man_term.o: man_term.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h man.h out.h term.h term_tag.h main.h +man_validate.o: man_validate.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h man.h libmandoc.h roff_int.h libman.h tag.h +mandoc.o: mandoc.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h libmandoc.h roff_int.h +mandoc_aux.o: mandoc_aux.c config.h mandoc.h mandoc_aux.h mandoc_dbg.h +mandoc_dbg.o: mandoc_dbg.c config.h compat_ohash.h mandoc_aux.h mandoc_dbg.h mandoc.h mandoc_msg.o: mandoc_msg.c config.h mandoc.h -mandoc_ohash.o: mandoc_ohash.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h -mandoc_xr.o: mandoc_xr.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc_xr.h -mandocd.o: mandocd.c config.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h -mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h -manpath.o: manpath.c config.h mandoc_aux.h mandoc.h manconf.h -mansearch.o: mansearch.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h -mdoc.o: mdoc.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h out.h html.h main.h -mdoc_macro.o: mdoc_macro.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h out.h main.h -mdoc_markdown.o: mdoc_markdown.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h main.h -mdoc_state.o: mdoc_state.c config.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h -mdoc_term.o: mdoc_term.c config.h mandoc_aux.h roff.h mdoc.h out.h term.h term_tag.h main.h -mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h tag.h +mandoc_ohash.o: mandoc_ohash.c config.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h +mandoc_xr.o: mandoc_xr.c config.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h mandoc_xr.h +mandocd.o: mandocd.c config.h mandoc.h mandoc_dbg.h roff.h mdoc.h man.h mandoc_parse.h main.h manconf.h +mandocdb.o: mandocdb.c config.h compat_fts.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h manconf.h mansearch.h dba_array.h dba.h +manpath.o: manpath.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h manconf.h +mansearch.o: mansearch.c config.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h manconf.h mansearch.h dbm.h +mdoc.o: mdoc.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_argv.o: mdoc_argv.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_html.o: mdoc_html.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h mdoc.h out.h html.h main.h +mdoc_macro.o: mdoc_macro.c config.h mandoc_dbg.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_man.o: mdoc_man.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h mdoc.h man.h out.h main.h +mdoc_markdown.o: mdoc_markdown.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h mdoc.h main.h +mdoc_state.o: mdoc_state.c config.h mandoc_dbg.h mandoc.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h +mdoc_term.o: mdoc_term.c config.h mandoc_aux.h mandoc_dbg.h roff.h mdoc.h out.h term.h term_tag.h main.h +mdoc_validate.o: mdoc_validate.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h mandoc_xr.h roff.h mdoc.h libmandoc.h roff_int.h libmdoc.h tag.h msec.o: msec.c config.h mandoc.h libmandoc.h msec.in -out.o: out.c config.h mandoc_aux.h mandoc.h tbl.h out.h +out.o: out.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h tbl.h out.h preconv.o: preconv.c config.h mandoc.h roff.h mandoc_parse.h libmandoc.h -read.o: read.c config.h mandoc_aux.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h tag.h -roff.o: roff.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mandoc_parse.h libmandoc.h roff_int.h tbl_parse.h eqn_parse.h predefs.in +read.o: read.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h roff.h mdoc.h man.h mandoc_parse.h libmandoc.h roff_int.h tag.h +roff.o: roff.c config.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h mandoc.h roff.h mandoc_parse.h libmandoc.h roff_int.h tbl_parse.h eqn_parse.h predefs.in roff_html.o: roff_html.c config.h mandoc.h roff.h out.h html.h roff_term.o: roff_term.c config.h mandoc.h roff.h out.h term.h roff_validate.o: roff_validate.c config.h mandoc.h roff.h libmandoc.h roff_int.h soelim.o: soelim.c config.h compat_stringlist.h st.o: st.c config.h mandoc.h roff.h libmdoc.h -tag.o: tag.c config.h mandoc_aux.h mandoc_ohash.h compat_ohash.h roff.h mdoc.h roff_int.h tag.h -tbl.o: tbl.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h -tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h -tbl_html.o: tbl_html.c config.h mandoc.h roff.h tbl.h out.h html.h -tbl_layout.o: tbl_layout.c config.h mandoc_aux.h mandoc.h tbl.h libmandoc.h tbl_int.h +tag.o: tag.c config.h mandoc_aux.h mandoc_dbg.h mandoc_ohash.h compat_ohash.h roff.h mdoc.h roff_int.h tag.h +tbl.o: tbl.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h tbl.h libmandoc.h tbl_parse.h tbl_int.h +tbl_data.o: tbl_data.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h tbl.h libmandoc.h tbl_int.h +tbl_html.o: tbl_html.c config.h mandoc_dbg.h mandoc.h roff.h tbl.h out.h html.h +tbl_layout.o: tbl_layout.c config.h mandoc_aux.h mandoc_dbg.h mandoc.h tbl.h libmandoc.h tbl_int.h tbl_opts.o: tbl_opts.c config.h mandoc.h tbl.h libmandoc.h tbl_int.h -tbl_term.o: tbl_term.c config.h mandoc.h tbl.h out.h term.h -term.o: term.c config.h mandoc.h mandoc_aux.h out.h term.h main.h -term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h out.h term.h manconf.h main.h -term_ps.o: term_ps.c config.h mandoc_aux.h out.h term.h manconf.h main.h -term_tab.o: term_tab.c config.h mandoc_aux.h out.h term.h +tbl_term.o: tbl_term.c config.h mandoc_dbg.h mandoc.h tbl.h out.h term.h +term.o: term.c config.h mandoc.h mandoc_aux.h mandoc_dbg.h out.h term.h main.h +term_ascii.o: term_ascii.c config.h mandoc.h mandoc_aux.h mandoc_dbg.h out.h term.h manconf.h main.h +term_ps.o: term_ps.c config.h mandoc_aux.h mandoc_dbg.h out.h term.h manconf.h main.h +term_tab.o: term_tab.c config.h mandoc_aux.h mandoc_dbg.h out.h term.h term_tag.o: term_tag.c config.h mandoc.h roff.h roff_int.h tag.h term_tag.h tree.o: tree.c config.h mandoc.h roff.h mdoc.h man.h tbl.h eqn.h main.h --- /dev/null +++ mandoc_dbg_init.3 @@ -0,0 +1,280 @@ +.\" $Id: mandoc_dbg_init.3,v 1.1 2022/04/14 16:43:44 schwarze Exp $ +.\" +.\" Copyright (c) 2021, 2022 Ingo Schwarze +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd $Mdocdate: April 14 2022 $ +.Dt MANDOC_DBG_INIT 3 +.Os +.Sh NAME +.Nm mandoc_dbg_init , +.Nm mandoc_dbg_name , +.Nm mandoc_dbg_finish +.Nd search for memory leaks in mandoc +.Sh SYNOPSIS +.Ft void +.Fn mandoc_dbg_init "int argc" "char *argv[]" +.Ft void +.Fn mandoc_dbg_name "const char *" +.Ft void +.Fn mandoc_dbg_finish void +.Sh DESCRIPTION +If the mandoc package is built with the line +.Ql DEBUG_MEMORY=1 +in the file +.Pa configure.local , +the functions documented in +.Xr mandoc_malloc 3 +and the function +.Xr free 3 +are instrumented to record every memory allocation in a dedicated +hash table and to check that every allocation is freed again. +This compile time option is only intended for binaries that are +used exclusively for debugging. +It is not intended for production binaries because it significantly +increases run time and memory usage and makes the programs more +fragile and more error-prone. +.Pp +The function +.Fn mandoc_dbg_init +initializes the memory debugging subsystem. +It is called from the top of the +.Fn main +programs, passing through the arguments that +.Fn main +received. +The +.Sx ENVIRONMENT +section of the present manual page explains how the +.Ev DEBUG_MEMORY +environment variable controls the amount and destination of reporting. +.Pp +The function +.Fn mandoc_dbg_name +is called from the +.Xr mdoc 7 +and +.Xr man 7 +parsers whenever a +.Ic \&Dt +or +.Ic \&TH +macro is parsed, passing the complete macro line as the argument. +.Pp +The function +.Fn mandoc_dbg_finish +performs cleanup and optionally final reporting. +It is called from the end of the +.Fn main +programs, just before normal termination. +.Pp +Getting the +.Sy #include +directives right for these functions is slightly tricky. +If a file already includes +.Qq Pa mandoc_aux.h , +no additional directive is needed because +.Qq Pa mandoc_aux.h +already includes +.Qq Pa mandoc_dgb.h +if +.Ql DEBUG_MEMORY=1 +is set in +.Pa configure.local . +.Pp +If a file does not need +.Qq Pa mandoc_aux.h +but calls a function documented in the present manual page and also calls +.Xr free 3 +directly, it needs this code before the other +.Xr mandoc_headers 3 : +.Bd -literal -offset indent +#if DEBUG_MEMORY +#include "mandoc_dbg.h" +#endif +.Ed +.Pp +If a file calls a function documented in the present manual page +but does not directly call +.Xr free 3 , +it can use this less intrusive idiom: +.Bd -literal -offset indent +#if DEBUG_MEMORY +#define DEBUG_NODEF +#include "mandoc_dbg.h" +#endif +.Ed +.Sh ENVIRONMENT +The environment variable +.Ev DEBUG_MEMORY +controls the amount and destination of reporting. +.Pp +If it is unset, diagnostic output is directed to standard error output +and only fatal errors are reported. +Even though full memory accounting is always performed +by any binary that was compiled with +.Ql DEBUG_MEMORY=1 , +resulting in a significant increase in both run time and memory usage, +memory leaks are +.Em not +reported when +.Ev DEBUG_MEMORY +is not set at run time. +.Pp +If +.Ev DEBUG_MEMORY +is set, it is interpreted as a string of flags. +The flags are as follows: +.Bl -tag -width 1n +.It Cm A +Log every allocation. +This produces huge amounts of output and is usually not needed +to find memory leaks. +Its main purpose is debugging the memory debugging subsystem itself. +.Pp +When enabled, allocations are logged in this format: +.Pp +.D1 Cm A Ar file Ns .c: Ns Ar line function Ns Po Fa nmemb , size Pc\ + No = Ar address +.Pp +The meaning of the fields is the same as for the +.Cm L +option. +.It Cm F +Log every +.Xr free 3 +and every reallocation where the memory to be released or reallocated +was allocated with one of the functions documented in +.Xr mandoc_malloc 3 . +Again, this produces huge amounts of output and is usually not +needed to find memory leaks, and its main purpose is debugging the +memory debugging subsystem itself. +.Pp +The logging format is: +.Pp +.D1 Cm F Ar file Ns .c: Ns Ar line function Ns Pq address +.Pp +It provides the name of the +.Ar file +and the number of the +.Ar line +in that file which called the +.Xr free 3 +or reallocation +.Ar function , +and the +.Fa address +that was given as an argument. +.Pp +If both the +.Cm A +and the +.Cm F +flags are enabled, calls to reallocation functions often log two lines, +first an +.Cm F +line reporting the address passed in as an argument, then an +.Cm A +line reporting the adress returned as the function return value. +.It Cm L +Log every memory leak. +For every allocation made after +.Fn mandoc_dbg_init +using functions documented in +.Xr mandoc_malloc 3 +that was not freed before +.Fn mandoc_dbg_finish , +print a line in this format: +.Pp +.D1 Cm L Ar file Ns .c: Ns Ar line function Ns Po Fa nmemb , size Pc\ + No = Ar address +.Pp +It provides the name of the +.Ar file +and the number of the +.Ar line +in that file which called the allocation +.Ar function +with the arguments +.Fa nmemb +and +.Fa size +documented for +.Xr calloc 3 . +If the +.Ar function +does not take an +.Fa nmemb +argument, +.Fa nmemb +is reported as 1. +At the end of the line, the virtual +.Ar address +of the memory returned from the allocation function is reported. +.It Cm N +Log the names of manual pages processed in the following formats: +.Bd -unfilled -offset indent +.Cm N Pf . Ic \&Dt Ar name section Op Ar architecture +.Cm N Pf . Ic \&TH Ar name section Op Ar additional arguments +.Ed +.Pp +This is particularly useful if a program crashes, runs out of memory, +or enters an infinite loop. +The last +.Cm N +line logged often indicates the input file triggering the problem. +.It Cm / +Interpret the rest of +.Ev DEBUG_MEMORY +as an absolute path and redirect debugging output to that file, +appending to the file if it already exists or creating it otherwise. +.El +.Pp +If +.Ev DEBUG_MEMORY +is set, even if it is empty, +.Fn mandoc_dbg_init +always writes the line +.Pp +.D1 Cm P Ar pid Sy \&[ Ns Ar progname Ns Sy \&]\ + Sy \&[ Ns Ar argument Ns Sy \&] Ar ... +.Pp +enclosing each element of +.Fa argv +in square brackets, to avoid that arguments containing whitespace +appear in the same way as multiple arguments, and +.Fn mandoc_dbg_finish +always writes the line: +.Pp +.D1 Cm S Ar number No memory leaks found +.Sh EXAMPLES +The following is a typical sequence of commands for finding memory +leaks in the parsers, in the HTML formatter, and in the regression suite: +.Bd -literal -offset indent +make distclean +echo BUILD_CATMAN=1 >> configure.local +echo DEBUG_MEMORY=1 >> configure.local +\&./configure +make +export DEBUG_MEMORY=NL/tmp/mandoc.debug.txt +mkdir Out +export PATH=$PATH:$(pwd) +\&./catman -T html /usr/share/man Out +make regress-clean +make regress +less /tmp/mandoc.debug.txt +.Ed +.Sh SEE ALSO +.Xr mandoc_malloc 3 , +.Xr catman 8 Index: mdoc_state.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/mdoc_state.c,v retrieving revision 1.17 retrieving revision 1.18 diff -Lmdoc_state.c -Lmdoc_state.c -u -p -r1.17 -r1.18 --- mdoc_state.c +++ mdoc_state.c @@ -1,6 +1,6 @@ /* $Id$ */ /* - * Copyright (c) 2014, 2015, 2017 Ingo Schwarze + * Copyright (c) 2014, 2015, 2017, 2021 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -23,6 +23,9 @@ #include #include +#if DEBUG_MEMORY +#include "mandoc_dbg.h" +#endif #include "mandoc.h" #include "roff.h" #include "mdoc.h" --- /dev/null +++ mandoc_dbg.c @@ -0,0 +1,342 @@ +/* $Id: mandoc_dbg.c,v 1.1 2022/04/14 16:43:44 schwarze Exp $ */ +/* + * Copyright (c) 2021, 2022 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include "config.h" + +#include + +#if HAVE_ERR +#include +#endif +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_OHASH +#include +#else +#include "compat_ohash.h" +#endif + +#define DEBUG_NODEF 1 +#include "mandoc_aux.h" +#include "mandoc.h" + +/* Store information about one allocation. */ +struct dhash_entry { + const char *file; + int line; + const char *func; + size_t num; + size_t size; + void *ptr; +}; + +/* Store information about all allocations. */ +static struct ohash dhash_table; +static FILE *dhash_fp; +static int dhash_aflag; +static int dhash_fflag; +static int dhash_lflag; +static int dhash_nflag; +static int dhash_sflag; + +static void *dhash_alloc(size_t, void *); +static void *dhash_calloc(size_t, size_t, void *); +static void dhash_free(void *, void *); +static unsigned int dhash_slot(void *); +static void dhash_register(const char *, int, const char *, + size_t, size_t, void *, const char *); +static void dhash_print(struct dhash_entry *); +static void dhash_purge(const char *, int, const char *, void *); + + +/* *** Debugging wrappers of public API functions. ************************ */ + +int +mandoc_dbg_asprintf(const char *file, int line, + char **dest, const char *fmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, fmt); + ret = vasprintf(dest, fmt, ap); + va_end(ap); + + if (ret == -1) + err((int)MANDOCLEVEL_SYSERR, NULL); + + dhash_register(file, line, "asprintf", 1, strlen(*dest) + 1, + *dest, *dest); + + return ret; +} + +void * +mandoc_dbg_calloc(size_t num, size_t size, const char *file, int line) +{ + void *ptr = mandoc_calloc(num, size); + dhash_register(file, line, "calloc", num, size, ptr, NULL); + return ptr; +} + +void * +mandoc_dbg_malloc(size_t size, const char *file, int line) +{ + void *ptr = mandoc_malloc(size); + dhash_register(file, line, "malloc", 1, size, ptr, NULL); + return ptr; +} + +void * +mandoc_dbg_realloc(void *ptr, size_t size, const char *file, int line) +{ + dhash_purge(file, line, "realloc", ptr); + ptr = mandoc_realloc(ptr, size); + dhash_register(file, line, "realloc", 1, size, ptr, NULL); + return ptr; +} + +void * +mandoc_dbg_reallocarray(void *ptr, size_t num, size_t size, + const char *file, int line) +{ + dhash_purge(file, line, "reallocarray", ptr); + ptr = mandoc_reallocarray(ptr, num, size); + dhash_register(file, line, "reallocarray", num, size, ptr, NULL); + return ptr; +} + +void * +mandoc_dbg_recallocarray(void *ptr, size_t oldnum, size_t num, size_t size, + const char *file, int line) +{ + dhash_purge(file, line, "recallocarray", ptr); + ptr = mandoc_recallocarray(ptr, oldnum, num, size); + dhash_register(file, line, "recallocarray", num, size, ptr, NULL); + return ptr; +} + +char * +mandoc_dbg_strdup(const char *ptr, const char *file, int line) +{ + char *p = mandoc_strdup(ptr); + dhash_register(file, line, "strdup", 1, strlen(p) + 1, p, ptr); + return p; +} + +char * +mandoc_dbg_strndup(const char *ptr, size_t sz, const char *file, int line) +{ + char *p = mandoc_strndup(ptr, sz); + dhash_register(file, line, "strndup", 1, strlen(p) + 1, p, NULL); + return p; +} + +void +mandoc_dbg_free(void *ptr, const char *file, int line) +{ + dhash_purge(file, line, "free", ptr); + free(ptr); +} + + +/* *** Memory allocation callbacks for the debugging table. *************** */ + +static void * +dhash_alloc(size_t sz, void *arg) +{ + return malloc(sz); +} + +static void * +dhash_calloc(size_t n, size_t sz, void *arg) +{ + return calloc(n, sz); +} + +static void +dhash_free(void *p, void *arg) +{ + free(p); +} + + +/* *** Debugging utility functions. *************************************** */ + +/* Initialize the debugging table, to be called from the top of main(). */ +void +mandoc_dbg_init(int argc, char *argv[]) +{ + struct ohash_info info; + char *dhash_fn; + int argi; + + info.alloc = dhash_alloc; + info.calloc = dhash_calloc; + info.free = dhash_free; + info.data = NULL; + info.key_offset = offsetof(struct dhash_entry, ptr); + ohash_init(&dhash_table, 18, &info); + + dhash_fp = stderr; + if ((dhash_fn = getenv("DEBUG_MEMORY")) == NULL) + return; + + dhash_sflag = 1; + for(;; dhash_fn++) { + switch (*dhash_fn) { + case '\0': + break; + case 'A': + dhash_aflag = 1; + continue; + case 'F': + dhash_fflag = 1; + continue; + case 'L': + dhash_lflag = 1; + continue; + case 'N': + dhash_nflag = 1; + continue; + case '/': + if ((dhash_fp = fopen(dhash_fn, "a+e")) == NULL) + err((int)MANDOCLEVEL_SYSERR, "%s", dhash_fn); + break; + default: + errx((int)MANDOCLEVEL_BADARG, + "invalid char '%c' in $DEBUG_MEMORY", + *dhash_fn); + } + break; + } + if (setvbuf(dhash_fp, NULL, _IOLBF, 0) != 0) + err((int)MANDOCLEVEL_SYSERR, "setvbuf"); + + fprintf(dhash_fp, "P %d", getpid()); + for (argi = 0; argi < argc; argi++) + fprintf(dhash_fp, " [%s]", argv[argi]); + fprintf(dhash_fp, "\n"); +} + +void +mandoc_dbg_name(const char *name) +{ + if (dhash_nflag) + fprintf(dhash_fp, "N %s\n", name); +} + +/* Hash a pointer and return the table slot currently used for it. */ +static unsigned int +dhash_slot(void *ptr) +{ + const char *ks, *ke; + uint32_t hv; + + ks = (const char *)&ptr; + ke = ks + sizeof(ptr); + hv = ohash_interval(ks, &ke); + return ohash_lookup_memory(&dhash_table, ks, sizeof(ptr), hv); +} + +/* Record one allocation in the debugging table. */ +static void +dhash_register(const char *file, int line, const char *func, + size_t num, size_t size, void *ptr, const char *str) +{ + struct dhash_entry *e; + unsigned int slot; + + slot = dhash_slot(ptr); + e = ohash_find(&dhash_table, slot); + if (dhash_aflag || e != NULL) { + fprintf(dhash_fp, "A %s:%d %s(%zu, %zu) = %p", + file, line, func, num, size, ptr); + if (str != NULL) + fprintf(dhash_fp, " \"%s\"", str); + fprintf(dhash_fp, "\n"); + } + if (e != NULL) { + dhash_print(e); + fprintf(dhash_fp, "E duplicate address %p\n", e->ptr); + errx((int)MANDOCLEVEL_BADARG, "duplicate address %p", e->ptr); + } + + if ((e = malloc(sizeof(*e))) == NULL) + err(1, NULL); + e->file = file; + e->line = line; + e->func = func; + e->num = num; + e->size = size; + e->ptr = ptr; + + ohash_insert(&dhash_table, slot, e); +} + +/* Remove one allocation from the debugging table. */ +static void +dhash_purge(const char *file, int line, const char *func, void *ptr) +{ + struct dhash_entry *e; + unsigned int slot; + + if (ptr == NULL) + return; + + if (dhash_fflag) + fprintf(dhash_fp, "F %s:%d %s(%p)\n", file, line, func, ptr); + + slot = dhash_slot(ptr); + e = ohash_remove(&dhash_table, slot); + free(e); +} + +/* Pretty-print information about one allocation. */ +static void +dhash_print(struct dhash_entry *e) +{ + fprintf(dhash_fp, "L %s:%d %s(%zu, %zu) = %p\n", + e->file, e->line, e->func, e->num, e->size, e->ptr); +} + +/* Pretty-print information about all active allocations. */ +void +mandoc_dbg_finish(void) +{ + struct dhash_entry *e; + unsigned int errcount, slot; + + errcount = ohash_entries(&dhash_table); + e = ohash_first(&dhash_table, &slot); + while (e != NULL) { + if (dhash_lflag) + dhash_print(e); + free(e); + e = ohash_next(&dhash_table, &slot); + } + ohash_delete(&dhash_table); + if (dhash_sflag) + fprintf(dhash_fp, "S %u memory leaks found\n", errcount); + if (dhash_fp != stderr) + fclose(dhash_fp); +} Index: configure =================================================================== RCS file: /home/cvs/mandoc/mandoc/configure,v retrieving revision 1.81 retrieving revision 1.82 diff -Lconfigure -Lconfigure -u -p -r1.81 -r1.82 --- configure +++ configure @@ -37,6 +37,7 @@ SOURCEDIR=`dirname "${0}"` MANPATH_BASE="/usr/share/man:/usr/X11R6/man" MANPATH_DEFAULT="/usr/share/man:/usr/X11R6/man:/usr/local/man" +DEBUG_MEMORY=0 OSENUM= OSNAME= UTF8_LOCALE= @@ -99,6 +100,7 @@ NEED_GNU_SOURCE=0 NEED_OPENBSD_SOURCE=0 NEED_XPG4_2=0 +DEBUG_OBJS= MANDOC_COBJS= SOELIM_COBJS= @@ -334,6 +336,7 @@ runtest vasprintf VASPRINTF "" -D_GNU_SO # --- fts --- if [ "${1}" = "-depend" ]; then + DEBUG_MEMORY=1 HAVE_FTS=0 HAVE_FTS_COMPARE_CONST=0 echo "tested fts: HAVE_FTS=0 (for make depend)" 1>&2 @@ -461,6 +464,10 @@ echo echo "#define MAN_CONF_FILE \"/etc/${MANM_MANCONF}\"" echo "#define MANPATH_BASE \"${MANPATH_BASE}\"" echo "#define MANPATH_DEFAULT \"${MANPATH_DEFAULT}\"" +if [ ${DEBUG_MEMORY} -ne 0 ]; then + echo "#define DEBUG_MEMORY ${DEBUG_MEMORY}" + DEBUG_OBJS=mandoc_dbg.o +fi echo "#define OSENUM ${OSENUM}" [ -n "${OSNAME}" ] && echo "#define OSNAME \"${OSNAME}\"" [ -n "${UTF8_LOCALE}" ] && echo "#define UTF8_LOCALE \"${UTF8_LOCALE}\"" @@ -640,6 +647,7 @@ CC = ${CC} CFLAGS = ${CFLAGS} LDADD = ${LDADD} LDFLAGS = ${LDFLAGS} +DEBUG_OBJS = ${DEBUG_OBJS} MANDOC_COBJS = ${MANDOC_COBJS} SOELIM_COBJS = ${SOELIM_COBJS} STATIC = ${STATIC} Index: main.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/main.c,v retrieving revision 1.360 retrieving revision 1.361 diff -Lmain.c -Lmain.c -u -p -r1.360 -r1.361 --- main.c +++ main.c @@ -149,11 +149,14 @@ main(int argc, char *argv[]) enum mandoc_os os_e; /* Check base system conventions. */ enum outmode outmode; /* According to command line. */ +#if DEBUG_MEMORY + mandoc_dbg_init(argc, argv); +#endif #if HAVE_PROGNAME progname = getprogname(); #else if (argc < 1) - progname = mandoc_strdup("mandoc"); + progname = "mandoc"; else if ((progname = strrchr(argv[0], '/')) == NULL) progname = argv[0]; else @@ -671,6 +674,9 @@ out: } else if (outst.had_output && outst.outtype != OUTT_LINT) mandoc_msg_summary(); +#if DEBUG_MEMORY + mandoc_dbg_finish(); +#endif return (int)mandoc_msg_getrc(); } Index: tbl_html.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/tbl_html.c,v retrieving revision 1.39 retrieving revision 1.40 diff -Ltbl_html.c -Ltbl_html.c -u -p -r1.39 -r1.40 --- tbl_html.c +++ tbl_html.c @@ -1,7 +1,7 @@ /* $Id$ */ /* - * Copyright (c) 2011 Kristaps Dzonsons * Copyright (c) 2014,2015,2017,2018,2021 Ingo Schwarze + * Copyright (c) 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -24,6 +24,9 @@ #include #include +#if DEBUG_MEMORY +#include "mandoc_dbg.h" +#endif #include "mandoc.h" #include "roff.h" #include "tbl.h" Index: configure.local.example =================================================================== RCS file: /home/cvs/mandoc/mandoc/configure.local.example,v retrieving revision 1.43 retrieving revision 1.44 diff -Lconfigure.local.example -Lconfigure.local.example -u -p -r1.43 -r1.44 --- configure.local.example +++ configure.local.example @@ -1,6 +1,6 @@ # $Id$ # -# Copyright (c) 2014-2021 Ingo Schwarze +# Copyright (c) 2014-2022 Ingo Schwarze # # Permission to use, copy, modify, and distribute this software for any # purpose with or without fee is hereby granted, provided that the above @@ -311,6 +311,12 @@ BINM_CATMAN=mcatman # default is "catma # unchanged, and nothing will be added. CFLAGS="-g" + +# Hunt for memory leaks. +# Do not use for production builds. +# See mandoc_dbg_init(3) for more information. + +DEBUG_MEMORY=1 # In rare cases, it may be required to skip individual automatic tests. # Each of the following variables can be set to 0 (test will not be run Index: mandoc_aux.h =================================================================== RCS file: /home/cvs/mandoc/mandoc/mandoc_aux.h,v retrieving revision 1.7 retrieving revision 1.8 diff -Lmandoc_aux.h -Lmandoc_aux.h -u -p -r1.7 -r1.8 --- mandoc_aux.h +++ mandoc_aux.h @@ -1,7 +1,7 @@ -/* $Id$ */ +/* $Id$ */ /* + * Copyright (c) 2014, 2017, 2021 Ingo Schwarze * Copyright (c) 2009, 2011 Kristaps Dzonsons - * Copyright (c) 2014, 2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,3 +25,7 @@ void *mandoc_reallocarray(void *, size void *mandoc_recallocarray(void *, size_t, size_t, size_t); char *mandoc_strdup(const char *); char *mandoc_strndup(const char *, size_t); + +#if DEBUG_MEMORY +#include "mandoc_dbg.h" +#endif Index: mandoc_aux.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/mandoc_aux.c,v retrieving revision 1.11 retrieving revision 1.12 diff -Lmandoc_aux.c -Lmandoc_aux.c -u -p -r1.11 -r1.12 --- mandoc_aux.c +++ mandoc_aux.c @@ -1,7 +1,7 @@ -/* $Id$ */ +/* $Id$ */ /* + * Copyright (c) 2014, 2015, 2017, 2018 Ingo Schwarze * Copyright (c) 2009, 2011 Kristaps Dzonsons - * Copyright (c) 2014, 2015, 2017 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -27,6 +27,7 @@ #include #include +#define DEBUG_NODEF 1 #include "mandoc.h" #include "mandoc_aux.h" Index: mdoc_macro.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/mdoc_macro.c,v retrieving revision 1.234 retrieving revision 1.235 diff -Lmdoc_macro.c -Lmdoc_macro.c -u -p -r1.234 -r1.235 --- mdoc_macro.c +++ mdoc_macro.c @@ -1,7 +1,7 @@ -/* $Id$ */ +/* $Id$ */ /* + * Copyright (c) 2010, 2012-2021 Ingo Schwarze * Copyright (c) 2008-2012 Kristaps Dzonsons - * Copyright (c) 2010, 2012-2020 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -26,6 +26,9 @@ #include #include +#if DEBUG_MEMORY +#include "mandoc_dbg.h" +#endif #include "mandoc.h" #include "roff.h" #include "mdoc.h" @@ -1510,6 +1513,11 @@ in_line_eoln(MACRO_PROT_ARGS) if (n->tok == MDOC_Nm) rew_last(mdoc, n->parent); } + +#if DEBUG_MEMORY + if (tok == MDOC_Dt) + mandoc_dbg_name(buf); +#endif if (buf[*pos] == '\0' && (tok == MDOC_Fd || *roff_name[tok] == '%')) { --- /dev/null +++ mandoc_dbg.h @@ -0,0 +1,55 @@ +/* $Id: mandoc_dbg.h,v 1.1 2022/04/14 16:43:44 schwarze Exp $ */ +/* + * Copyright (c) 2021 Ingo Schwarze + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +int mandoc_dbg_asprintf(const char *, int, char **, const char *, ...) + __attribute__((__format__ (__printf__, 4, 5))); +void *mandoc_dbg_calloc(size_t, size_t, const char *, int); +void *mandoc_dbg_malloc(size_t, const char *, int); +void *mandoc_dbg_realloc(void *, size_t, const char *, int); +void *mandoc_dbg_reallocarray(void *, size_t, size_t, + const char *, int); +void *mandoc_dbg_recallocarray(void *, size_t, size_t, size_t, + const char *, int); +char *mandoc_dbg_strdup(const char *, const char *, int); +char *mandoc_dbg_strndup(const char *, size_t, const char *, int); +void mandoc_dbg_free(void *, const char *, int); + +void mandoc_dbg_init(int argc, char *argv[]); +void mandoc_dbg_name(const char *); +void mandoc_dbg_finish(void); + +#ifndef DEBUG_NODEF +#define mandoc_asprintf(dest, fmt, ...) \ + mandoc_dbg_asprintf(__FILE__, __LINE__, (dest), (fmt), __VA_ARGS__) +#define mandoc_calloc(num, size) \ + mandoc_dbg_calloc((num), (size), __FILE__, __LINE__) +#define mandoc_malloc(size) \ + mandoc_dbg_malloc((size), __FILE__, __LINE__) +#define mandoc_realloc(ptr, size) \ + mandoc_dbg_realloc((ptr), (size), __FILE__, __LINE__) +#define mandoc_reallocarray(ptr, num, size) \ + mandoc_dbg_reallocarray((ptr), (num), (size), __FILE__, __LINE__) +#define mandoc_recallocarray(ptr, old, num, size) \ + mandoc_dbg_recallocarray((ptr), (old), (num), (size), \ + __FILE__, __LINE__) +#define mandoc_strdup(ptr) \ + mandoc_dbg_strdup((ptr), __FILE__, __LINE__) +#define mandoc_strndup(ptr, size) \ + mandoc_dbg_strndup((ptr), (size), __FILE__, __LINE__) +#define free(ptr) \ + mandoc_dbg_free((ptr), __FILE__, __LINE__) +#endif Index: mandocd.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/mandocd.c,v retrieving revision 1.12 retrieving revision 1.13 diff -Lmandocd.c -Lmandocd.c -u -p -r1.12 -r1.13 --- mandocd.c +++ mandocd.c @@ -1,7 +1,7 @@ -/* $Id$ */ +/* $Id$ */ /* * Copyright (c) 2017 Michael Stapelberg - * Copyright (c) 2017, 2019 Ingo Schwarze + * Copyright (c) 2017, 2019, 2021 Ingo Schwarze * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,6 +35,10 @@ #include #include "mandoc.h" +#if DEBUG_MEMORY +#define DEBUG_NODEF 1 +#include "mandoc_dbg.h" +#endif #include "roff.h" #include "mdoc.h" #include "man.h" @@ -129,6 +133,10 @@ main(int argc, char *argv[]) int state, opt; enum outt outtype; +#if DEBUG_MEMORY + mandoc_dbg_init(argc, argv); +#endif + defos = NULL; outtype = OUTT_ASCII; while ((opt = getopt(argc, argv, "I:T:")) != -1) { @@ -240,6 +248,9 @@ main(int argc, char *argv[]) } mparse_free(parser); mchars_free(); +#if DEBUG_MEMORY + mandoc_dbg_finish(); +#endif return state == -1 ? 1 : 0; } Index: tbl_term.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/tbl_term.c,v retrieving revision 1.76 retrieving revision 1.77 diff -Ltbl_term.c -Ltbl_term.c -u -p -r1.76 -r1.77 --- tbl_term.c +++ tbl_term.c @@ -1,7 +1,7 @@ -/* $Id$ */ +/* $Id$ */ /* - * Copyright (c) 2009, 2011 Kristaps Dzonsons * Copyright (c) 2011-2021 Ingo Schwarze + * Copyright (c) 2009, 2011 Kristaps Dzonsons * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,6 +25,9 @@ #include #include +#if DEBUG_MEMORY +#include "mandoc_dbg.h" +#endif #include "mandoc.h" #include "tbl.h" #include "out.h" Index: demandoc.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/demandoc.c,v retrieving revision 1.33 retrieving revision 1.34 diff -Ldemandoc.c -Ldemandoc.c -u -p -r1.33 -r1.34 --- demandoc.c +++ demandoc.c @@ -1,4 +1,4 @@ -/* $Id$ */ +/* $Id$ */ /* * Copyright (c) 2011 Kristaps Dzonsons * @@ -26,6 +26,10 @@ #include #include "mandoc.h" +#if DEBUG_MEMORY +#define DEBUG_NODEF +#include "mandoc_dbg.h" +#endif #include "roff.h" #include "man.h" #include "mdoc.h" @@ -47,6 +51,10 @@ main(int argc, char *argv[]) int ch, fd, i, list; extern int optind; +#if DEBUG_MEMORY + mandoc_dbg_init(argc, argv); +#endif + if (argc < 1) progname = "demandoc"; else if ((progname = strrchr(argv[0], '/')) == NULL) @@ -97,6 +105,9 @@ main(int argc, char *argv[]) mparse_free(mp); mchars_free(); +#if DEBUG_MEMORY + mandoc_dbg_finish(); +#endif return (int)MANDOCLEVEL_OK; } Index: man_macro.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/man_macro.c,v retrieving revision 1.146 retrieving revision 1.147 diff -Lman_macro.c -Lman_macro.c -u -p -r1.146 -r1.147 --- man_macro.c +++ man_macro.c @@ -26,6 +26,9 @@ #include #include +#if DEBUG_MEMORY +#include "mandoc_dbg.h" +#endif #include "mandoc.h" #include "roff.h" #include "man.h" @@ -393,6 +396,11 @@ in_line_eoln(MACRO_PROT_ARGS) man->flags |= ROFF_NOFILL; else if (tok == MAN_EE) man->flags &= ~ROFF_NOFILL; + +#if DEBUG_MEMORY + if (tok == MAN_TH) + mandoc_dbg_name(buf); +#endif for (;;) { if (buf[*pos] != '\0' && man->last != n && tok == MAN_PD) { Index: mandocdb.c =================================================================== RCS file: /home/cvs/mandoc/mandoc/mandocdb.c,v retrieving revision 1.270 retrieving revision 1.271 diff -Lmandocdb.c -Lmandocdb.c -u -p -r1.270 -r1.271 --- mandocdb.c +++ mandocdb.c @@ -1,6 +1,6 @@ /* $Id$ */ /* - * Copyright (c) 2011-2020 Ingo Schwarze + * Copyright (c) 2011-2021 Ingo Schwarze * Copyright (c) 2011, 2012 Kristaps Dzonsons * Copyright (c) 2016 Ed Maste * @@ -533,7 +533,7 @@ out: ohash_delete(&mpages); ohash_delete(&mlinks); #if DEBUG_MEMORY - mandoc_d_finish(); + mandoc_dbg_finish(); #endif return exitcode; usage: Index: Makefile =================================================================== RCS file: /home/cvs/mandoc/mandoc/Makefile,v retrieving revision 1.540 retrieving revision 1.541 diff -LMakefile -LMakefile -u -p -r1.540 -r1.541 --- Makefile +++ Makefile @@ -1,6 +1,6 @@ # $Id$ # -# Copyright (c) 2011, 2013-2021 Ingo Schwarze +# Copyright (c) 2011, 2013-2022 Ingo Schwarze # Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons # # Permission to use, copy, modify, and distribute this software for any @@ -100,6 +100,7 @@ SRCS = arch.c \ man_validate.c \ mandoc.c \ mandoc_aux.c \ + mandoc_dbg.c \ mandoc_msg.c \ mandoc_ohash.c \ mandoc_xr.c \ @@ -186,6 +187,8 @@ DISTFILES = INSTALL \ mandoc.h \ mandoc_aux.h \ mandoc_char.7 \ + mandoc_dbg.h \ + mandoc_dbg_init.3 \ mandoc_escape.3 \ mandoc_headers.3 \ mandoc_html.3 \ @@ -241,6 +244,7 @@ LIBROFF_OBJS = eqn.o \ LIBMANDOC_OBJS = $(LIBMAN_OBJS) \ $(LIBMDOC_OBJS) \ $(LIBROFF_OBJS) \ + $(DEBUG_OBJS) \ arch.o \ chars.o \ mandoc.o \ @@ -333,6 +337,7 @@ WWW_MANS = apropos.1.html \ soelim.1.html \ man.cgi.3.html \ mandoc.3.html \ + mandoc_dbg_init.3.html \ mandoc_escape.3.html \ mandoc_headers.3.html \ mandoc_html.3.html \ Index: mandoc_headers.3 =================================================================== RCS file: /home/cvs/mandoc/mandoc/mandoc_headers.3,v retrieving revision 1.34 retrieving revision 1.35 diff -Lmandoc_headers.3 -Lmandoc_headers.3 -u -p -r1.34 -r1.35 --- mandoc_headers.3 +++ mandoc_headers.3 @@ -1,6 +1,6 @@ -.\" $Id$ +.\" $Id$ .\" -.\" Copyright (c) 2014-2021 Ingo Schwarze +.\" Copyright (c) 2014-2022 Ingo Schwarze .\" .\" Permission to use, copy, modify, and distribute this software for any .\" purpose with or without fee is hereby granted, provided that the above @@ -25,8 +25,8 @@ To support a cleaner coding style, the m contain any include directives and do not guard against multiple inclusion. The application developer has to make sure that the headers are -included in a proper order, and that no header is included more -than once. +included in the order shown in this manual page, +and that no header is included more than once. .Pp The headers and functions form three major groups: .Sx Parser interface , @@ -83,6 +83,33 @@ for .Pp Provides the functions documented in .Xr mandoc_malloc 3 . +.Pp +When this header is included, the same file must not include +.Qq Pa mandoc_dbg.h +because +.Qq Pa mandoc_aux.h +automatically includes +.Qq Pa mandoc_dbg.h +if and only if the preprocessor symbol +.Dv DEBUG_MEMORY +is defined. +.It Qq Pa mandoc_dbg.h +Debugging utility functions and +debugging wrappers around memory allocation functions. +.Pp +Requires +.In sys/types.h +for +.Vt size_t . +.Pp +Provides the functions documented in +.Xr mandoc_dbg_init 3 . +.Pp +This header must not be included unless the preprocessor symbol +.Dv DEBUG_MEMORY +is defined. +When this header is included, the same file must not include +.Qq Pa mandoc_aux.h . .It Qq Pa mandoc_ohash.h Hashing utility functions; can be used everywhere. .Pp -- To unsubscribe send an email to source+unsubscribe@mandoc.bsd.lv