aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorIngo Schwarze <schwarze@openbsd.org>2022-04-14 16:43:43 +0000
committerIngo Schwarze <schwarze@openbsd.org>2022-04-14 16:43:43 +0000
commit792b9c4c5a44280611945547a57ac9e48af5baf1 (patch)
tree015fb8a15f37966559de140db370509df4737a1a
parent31a9a3fd6b1a2eec3fc1f35e538b7cc8726acfe4 (diff)
downloadmandoc-792b9c4c5a44280611945547a57ac9e48af5baf1.tar.gz
mandoc-792b9c4c5a44280611945547a57ac9e48af5baf1.tar.zst
mandoc-792b9c4c5a44280611945547a57ac9e48af5baf1.zip
support for hunting memory leaks;
designed and written last autumn, polished today
-rw-r--r--Makefile9
-rw-r--r--Makefile.depend89
-rwxr-xr-xconfigure10
-rw-r--r--configure.local.example10
-rw-r--r--demandoc.c13
-rw-r--r--main.c10
-rw-r--r--man_macro.c10
-rw-r--r--mandoc_aux.c5
-rw-r--r--mandoc_aux.h8
-rw-r--r--mandoc_dbg.c342
-rw-r--r--mandoc_dbg.h55
-rw-r--r--mandoc_dbg_init.3280
-rw-r--r--mandoc_headers.337
-rw-r--r--mandocd.c15
-rw-r--r--mandocdb.c6
-rw-r--r--mdoc_macro.c12
-rw-r--r--mdoc_state.c7
-rw-r--r--tbl_html.c7
-rw-r--r--tbl_term.c7
19 files changed, 857 insertions, 75 deletions
diff --git a/Makefile b/Makefile
index 48c47418..8acd5db5 100644
--- 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 \
diff --git a/Makefile.depend b/Makefile.depend
index d5f6556c..5179e95d 100644
--- a/Makefile.depend
+++ b/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 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
diff --git a/configure b/configure
index 5cf4e081..ef4a5841 100755
--- 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}
diff --git a/configure.local.example b/configure.local.example
index 1050f4a1..d5b260ea 100644
--- a/configure.local.example
+++ b/configure.local.example
@@ -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
diff --git a/demandoc.c b/demandoc.c
index 57d0cc5f..15f57d6d 100644
--- a/demandoc.c
+++ b/demandoc.c
@@ -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>
*
@@ -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;
}
diff --git a/main.c b/main.c
index 9f878ff5..aa997041 100644
--- 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();
}
diff --git a/man_macro.c b/man_macro.c
index 40033a66..da560c49 100644
--- a/man_macro.c
+++ b/man_macro.c
@@ -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,
diff --git a/mandoc_aux.c b/mandoc_aux.c
index 5d595ce0..47e15021 100644
--- a/mandoc_aux.c
+++ b/mandoc_aux.c
@@ -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"
diff --git a/mandoc_aux.h b/mandoc_aux.h
index 469e331e..342e3d72 100644
--- a/mandoc_aux.h
+++ b/mandoc_aux.h
@@ -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
index 00000000..7d5bf3b9
--- /dev/null
+++ b/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);
+}
diff --git a/mandoc_dbg.h b/mandoc_dbg.h
new file mode 100644
index 00000000..33e53be3
--- /dev/null
+++ b/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
diff --git a/mandoc_dbg_init.3 b/mandoc_dbg_init.3
new file mode 100644
index 00000000..6f9660db
--- /dev/null
+++ b/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
diff --git a/mandoc_headers.3 b/mandoc_headers.3
index 7fe6d379..ae01c7bf 100644
--- a/mandoc_headers.3
+++ b/mandoc_headers.3
@@ -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
diff --git a/mandocd.c b/mandocd.c
index 60e40fed..ccc846bd 100644
--- 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
@@ -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;
}
diff --git a/mandocdb.c b/mandocdb.c
index 13fbf2f8..2077176e 100644
--- a/mandocdb.c
+++ b/mandocdb.c
@@ -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:
diff --git a/mdoc_macro.c b/mdoc_macro.c
index dd3885c7..889b80a6 100644
--- a/mdoc_macro.c
+++ b/mdoc_macro.c
@@ -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,
diff --git a/mdoc_state.c b/mdoc_state.c
index d696ff27..9fa0f494 100644
--- a/mdoc_state.c
+++ b/mdoc_state.c
@@ -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"
diff --git a/tbl_html.c b/tbl_html.c
index 908bb4c8..7fd1c42d 100644
--- a/tbl_html.c
+++ b/tbl_html.c
@@ -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"
diff --git a/tbl_term.c b/tbl_term.c
index d83a97b8..ac826a5c 100644
--- a/tbl_term.c
+++ b/tbl_term.c
@@ -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"