* mandoc: support for hunting memory leaks; designed and written last
@ 2022-04-14 16:44 schwarze
0 siblings, 0 replies; only message in thread
From: schwarze @ 2022-04-14 16:44 UTC (permalink / raw)
To: source
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 <schwarze@openbsd.org>
+.\"
+.\" 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 <schwarze@openbsd.org>
+ * Copyright (c) 2014, 2015, 2017, 2021 Ingo Schwarze <schwarze@openbsd.org>
*
* 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 <stdlib.h>
#include <string.h>
+#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 <schwarze@openbsd.org>
+ *
+ * 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 <sys/types.h>
+
+#if HAVE_ERR
+#include <err.h>
+#endif
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#if HAVE_OHASH
+#include <ohash.h>
+#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 <kristaps@bsd.lv>
* Copyright (c) 2014,2015,2017,2018,2021 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* 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 <stdlib.h>
#include <string.h>
+#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 <schwarze@openbsd.org>
+# Copyright (c) 2014-2022 Ingo Schwarze <schwarze@openbsd.org>
#
# 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 <schwarze@openbsd.org>
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2017 Ingo Schwarze <schwarze@openbsd.org>
*
* 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 <schwarze@openbsd.org>
* Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2014, 2015, 2017 Ingo Schwarze <schwarze@openbsd.org>
*
* 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 <stdio.h>
#include <string.h>
+#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 <schwarze@openbsd.org>
* Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
- * Copyright (c) 2010, 2012-2020 Ingo Schwarze <schwarze@openbsd.org>
*
* 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 <string.h>
#include <time.h>
+#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 <schwarze@openbsd.org>
+ *
+ * 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 <stapelberg@debian.org>
- * Copyright (c) 2017, 2019 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2017, 2019, 2021 Ingo Schwarze <schwarze@openbsd.org>
*
* 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 <unistd.h>
#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 <kristaps@bsd.lv>
* Copyright (c) 2011-2021 Ingo Schwarze <schwarze@openbsd.org>
+ * Copyright (c) 2009, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
*
* 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 <stdlib.h>
#include <string.h>
+#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 <kristaps@bsd.lv>
*
@@ -26,6 +26,10 @@
#include <unistd.h>
#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 <stdlib.h>
#include <string.h>
+#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 <schwarze@openbsd.org>
+ * Copyright (c) 2011-2021 Ingo Schwarze <schwarze@openbsd.org>
* Copyright (c) 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
* Copyright (c) 2016 Ed Maste <emaste@freebsd.org>
*
@@ -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 <schwarze@openbsd.org>
+# Copyright (c) 2011, 2013-2022 Ingo Schwarze <schwarze@openbsd.org>
# Copyright (c) 2010, 2011, 2012 Kristaps Dzonsons <kristaps@bsd.lv>
#
# 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 <schwarze@openbsd.org>
+.\" Copyright (c) 2014-2022 Ingo Schwarze <schwarze@openbsd.org>
.\"
.\" 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
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2022-04-14 16:44 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-04-14 16:44 mandoc: support for hunting memory leaks; designed and written last schwarze
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).