]> git.cameronkatri.com Git - mandoc.git/commitdiff
support for hunting memory leaks;
authorIngo Schwarze <schwarze@openbsd.org>
Thu, 14 Apr 2022 16:43:43 +0000 (16:43 +0000)
committerIngo Schwarze <schwarze@openbsd.org>
Thu, 14 Apr 2022 16:43:43 +0000 (16:43 +0000)
designed and written last autumn, polished today

19 files changed:
Makefile
Makefile.depend
configure
configure.local.example
demandoc.c
main.c
man_macro.c
mandoc_aux.c
mandoc_aux.h
mandoc_dbg.c [new file with mode: 0644]
mandoc_dbg.h [new file with mode: 0644]
mandoc_dbg_init.3 [new file with mode: 0644]
mandoc_headers.3
mandocd.c
mandocdb.c
mdoc_macro.c
mdoc_state.c
tbl_html.c
tbl_term.c

index 48c4741812b62a3be4520d648ea8392a695c5688..8acd5db5193ca311f90a94703623826a9fccc16f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
-# $Id: Makefile,v 1.540 2021/09/21 11:04:40 schwarze Exp $
+# $Id: Makefile,v 1.541 2022/04/14 16:43:43 schwarze Exp $
 #
-# 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 d5f6556c3e7ebb4d8e0af2846fa69905bda9e8d5..5179e95d4715252533154c4333c04a0201f4f2cc 100644 (file)
@@ -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 config.h
 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
index 5cf4e081c2cb2a8c847ac3997b2cd9e16f7eee08..ef4a5841d2fc80e0d26b9bd5f6d49488447d0652 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #!/bin/sh
 #
-# $Id: configure,v 1.81 2021/09/20 10:19:51 schwarze Exp $
+# $Id: configure,v 1.82 2022/04/14 16:43:43 schwarze Exp $
 #
 # Copyright (c) 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
 #
@@ -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_SOURCE || true
 
 # --- 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 1050f4a1d9ab8cf80b766c34ece7e685928b4998..d5b260ea9326e8b00c142f1b583ef23c54ec14aa 100644 (file)
@@ -1,6 +1,6 @@
-# $Id: configure.local.example,v 1.43 2021/09/20 13:25:42 schwarze Exp $
+# $Id: configure.local.example,v 1.44 2022/04/14 16:43:43 schwarze Exp $
 #
-# 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
@@ -312,6 +312,12 @@ BINM_CATMAN=mcatman                # default is "catman"
 
 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
 # and will be regarded as failed) or 1 (test will not be run and will
index 57d0cc5f4120dee213091c638803161c87948ea2..15f57d6d4d8a712058df727bf3605cee9e23060c 100644 (file)
@@ -1,4 +1,4 @@
-/*     $Id: demandoc.c,v 1.33 2019/03/03 11:01:15 schwarze Exp $ */
+/* $Id: demandoc.c,v 1.34 2022/04/14 16:43:43 schwarze Exp $ */
 /*
  * Copyright (c) 2011 Kristaps Dzonsons <kristaps@bsd.lv>
  *
 #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;
 }
 
diff --git a/main.c b/main.c
index 9f878ff5200ef250977c4fb07ece283293218e91..aa997041b234555aeb66c79f2b16ed0f5ddad070 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,4 +1,4 @@
-/* $Id: main.c,v 1.360 2021/10/04 21:29:17 schwarze Exp $ */
+/* $Id: main.c,v 1.361 2022/04/14 16:43:43 schwarze Exp $ */
 /*
  * Copyright (c) 2010-2012, 2014-2021 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008-2012 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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 40033a6629932bb471061acdd75b70e106d7dd3e..da560c49f4f9b2ba6706bb70bd50b41beb44560c 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: man_macro.c,v 1.146 2022/04/13 14:45:50 schwarze Exp $ */
+/* $Id: man_macro.c,v 1.147 2022/04/14 16:43:44 schwarze Exp $ */
 /*
  * Copyright (c) 2012-2015,2017-2020,2022 Ingo Schwarze <schwarze@openbsd.org>
  * Copyright (c) 2008, 2009, 2010, 2011 Kristaps Dzonsons <kristaps@bsd.lv>
@@ -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"
@@ -394,6 +397,11 @@ in_line_eoln(MACRO_PROT_ARGS)
        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) {
                        mandoc_msg(MANDOCERR_ARG_EXCESS, line, *pos,
index 5d595ce0c29297ef730cf0ab026cd26a76a4b9cf..47e150218eee80d20b52e904c052fa759c0d3420 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: mandoc_aux.c,v 1.11 2018/02/07 20:04:57 schwarze Exp $ */
+/* $Id: mandoc_aux.c,v 1.12 2022/04/14 16:43:44 schwarze Exp $ */
 /*
+ * 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 469e331eb4bfa456b354298af5a5f6c548e188a5..342e3d721e246510c512cf6db4d6b6ac212fbaf0 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: mandoc_aux.h,v 1.7 2017/06/12 19:05:47 schwarze Exp $ */
+/* $Id: mandoc_aux.h,v 1.8 2022/04/14 16:43:44 schwarze Exp $ */
 /*
+ * 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_t, size_t);
 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
diff --git a/mandoc_dbg.c b/mandoc_dbg.c
new file mode 100644 (file)
index 0000000..7d5bf3b
--- /dev/null
@@ -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);
+}
diff --git a/mandoc_dbg.h b/mandoc_dbg.h
new file mode 100644 (file)
index 0000000..33e53be
--- /dev/null
@@ -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
diff --git a/mandoc_dbg_init.3 b/mandoc_dbg_init.3
new file mode 100644 (file)
index 0000000..6f9660d
--- /dev/null
@@ -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 7fe6d379f864894d41d5fe2318a80a5c206925e8..ae01c7bf6bb68514523955c42d82b51e8e211f08 100644 (file)
@@ -1,6 +1,6 @@
-.\"    $Id: mandoc_headers.3,v 1.34 2021/08/10 12:55:03 schwarze Exp $
+.\" $Id: mandoc_headers.3,v 1.35 2022/04/14 16:43:44 schwarze Exp $
 .\"
-.\" 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
@@ -14,7 +14,7 @@
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: August 10 2021 $
+.Dd $Mdocdate: April 14 2022 $
 .Dt MANDOC_HEADERS 3
 .Os
 .Sh NAME
@@ -25,8 +25,8 @@ To support a cleaner coding style, the mandoc header files do not
 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
index 60e40fed80239642fb0faf8b99f775ef6eae707f..ccc846bd03106f64b918e63bb16474a5c319d3a7 100644 (file)
--- a/mandocd.c
+++ b/mandocd.c
@@ -1,7 +1,7 @@
-/*     $Id: mandocd.c,v 1.12 2020/06/14 23:40:31 schwarze Exp $ */
+/* $Id: mandocd.c,v 1.13 2022/04/14 16:43:44 schwarze Exp $ */
 /*
  * 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
 #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 13fbf2f851dabac599b8bc01b617bcd0055cf0bf..2077176e08e8c7bec81244e8761542f90ea1fc2d 100644 (file)
@@ -1,6 +1,6 @@
-/* $Id: mandocdb.c,v 1.270 2021/11/05 17:04:10 schwarze Exp $ */
+/* $Id: mandocdb.c,v 1.271 2022/04/14 16:43:44 schwarze Exp $ */
 /*
- * 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 dd3885c702b737dfc992d04a1eb5467ead161605..889b80a64a685b393aa008ff285a6c64949f1f79 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: mdoc_macro.c,v 1.234 2020/01/19 18:02:00 schwarze Exp $ */
+/* $Id: mdoc_macro.c,v 1.235 2022/04/14 16:43:44 schwarze Exp $ */
 /*
+ * 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"
@@ -1511,6 +1514,11 @@ in_line_eoln(MACRO_PROT_ARGS)
                        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] == '%')) {
                mandoc_msg(MANDOCERR_MACRO_EMPTY,
index d696ff27e06c40075b8f8805c3d2a9515ef2ee4d..9fa0f494fae3529e8c86a278d38c89f274a5ed50 100644 (file)
@@ -1,6 +1,6 @@
-/* $Id: mdoc_state.c,v 1.17 2020/06/22 19:20:40 schwarze Exp $ */
+/* $Id: mdoc_state.c,v 1.18 2022/04/14 16:43:44 schwarze Exp $ */
 /*
- * 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"
index 908bb4c8b713c8169055e542b4f936df1e78489c..7fd1c42ddb1fcb9c16f00292f51a32cbe0c2e1a3 100644 (file)
@@ -1,7 +1,7 @@
-/* $Id: tbl_html.c,v 1.39 2022/01/12 04:43:26 schwarze Exp $ */
+/* $Id: tbl_html.c,v 1.40 2022/04/14 16:43:44 schwarze Exp $ */
 /*
- * 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 d83a97b8aa3ddc650e2d6aebc6d066f11e35873b..ac826a5cb363a2c98a104a0d957cc6d8d4f80f37 100644 (file)
@@ -1,7 +1,7 @@
-/*     $Id: tbl_term.c,v 1.76 2022/04/08 16:53:45 schwarze Exp $ */
+/* $Id: tbl_term.c,v 1.77 2022/04/14 16:43:44 schwarze Exp $ */
 /*
- * 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"