[bug #68585] [pic, tbl] code not "ASAN_OPTIONS=alloc_dealloc_mismatch=1" clean

"G. Branden Robinson" <[email protected]> Fri, 31 Jul 2026 15:53:16 -0400 (EDT)
Newsgroups gmane.comp.printing.groff.bugs
Message-ID <[email protected]>
--8323329-1714636915-1785527596=:2042551
Content-Type: TEXT/plain; CHARSET=utf-8
Content-Transfer-Encoding: QUOTED-PRINTABLE
Content-Disposition: inline

URL:=0A  <https://savannah.gnu.org/bugs/?68585>=0A=0A                 Summa=
ry: [pic,tbl] code not=0A"ASAN_OPTIONS=3Dalloc_dealloc_mismatch=3D1" clean=
=0A                   Group: GNU roff=0A               Submitter: gbranden=
=0A               Submitted: Fri 31 Jul 2026 07:53:12 PM UTC=0A            =
    Category: Preprocessor - others/general=0A                Severity: 3 -=
 Normal=0A              Item Group: Incorrect behaviour=0A                 =
 Status: Confirmed=0A                 Privacy: Public=0A             Assign=
ed to: None=0A             Open/Closed: Open=0A         Discussion Lock: Un=
locked=0A         Planned Release: None=0A=0A=0A    _______________________=
________________________________=0A=0AFollow-up Comments:=0A=0A=0A---------=
----------------------------------------------=0ADate: Fri 31 Jul 2026 07:5=
3:12 PM UTC By: G. Branden Robinson <gbranden>=0ABruno reported [https://li=
sts.gnu.org/archive/html/groff/2026-07/msg00055.html=0Athese] [https://list=
s.gnu.org/archive/html/groff/2026-07/msg00057.html issues]=0Ato the _groff_=
 list.=0A=0A=0AI tried building the groff-1.25.0.rc1 with clang's ASAN.=0AT=
he next error (during "make -k check"):=0A=0A  GROFF    doc/groff-man-pages=
.pdf=0A=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=3D=3D850834=3D=3D=
ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator=0A=0Ade=
lete []) on 0x7051a6beb4e0=0A    #0 0x590f7622b86d in operator delete[](voi=
d*) =0A/home/runner/work/llvm-project/llvm-project/compiler-rt/lib/asan/asa=
n_new_delete.cpp:179:46=0A    #1 0x590f7624cdff in block_entry::~block_entr=
y() =0A/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:=
667:3=0A    #2 0x590f76282a24 in left_block_entry::~left_block_entry() =0A/=
build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:334:7=0A=
    #3 0x590f76282a74 in left_block_entry::~left_block_entry() =0A/build/gr=
off-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:334:7=0A    #4 0=
x590f7625ce86 in table::~table() =0A/build/groff-1.25.0.rc1/build-64-clang/=
../src/preproc/tbl/table.cpp:1309:5=0A    #5 0x590f7622e9fc in process_tabl=
e(table_input&) =0A/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tb=
l/main.cpp:1667:5=0A    #6 0x590f7622dda7 in process_input_file(_IO_FILE*) =
=0A/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:270:4=
=0A    #7 0x590f76243bee in main =0A/build/groff-1.25.0.rc1/build-64-clang/=
../src/preproc/tbl/main.cpp:1782:5=0A    #8 0x73f1a782a600 in __libc_start_=
call_main =0Acsu/../sysdeps/nptl/libc_start_call_main.h:59:16=0A    #9 0x73=
f1a782a717 in __libc_start_main csu/../csu/libc-start.c:360:3=0A    #10 0x5=
90f76142984 in _start =0A(/build/groff-1.25.0.rc1/build-64-clang/tbl+0x5e98=
4)=0A=0A0x7051a6beb4e0 is located 0 bytes inside of 62-byte region =0A[0x70=
51a6beb4e0,0x7051a6beb51e)=0Aallocated by thread T0 here:=0A    #0 0x590f76=
1e7f39 in calloc =0A/home/runner/work/llvm-project/llvm-project/compiler-rt=
/lib/asan/asan_malloc_linux.cpp:74:3=0A    #1 0x590f7628be7a in string::ext=
ract() const =0A/build/groff-1.25.0.rc1/build-64-clang/../src/libs/libgroff=
/string.cpp:384:33=0A    #2 0x590f76263398 in table::add_entry(int, int, st=
ring const&,=0Aentry_format =0Aconst*, char const*, int) =0A/build/groff-1.=
25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:1545:17=0A    #3 0x590=
f76240b46 in process_data(table_input&, format*, options*) =0A/build/groff-=
1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:1567:13=0A    #4 0x59=
0f7622e972 in process_table(table_input&) =0A/build/groff-1.25.0.rc1/build-=
64-clang/../src/preproc/tbl/main.cpp:1665:17=0A    #5 0x590f7622dda7 in pro=
cess_input_file(_IO_FILE*) =0A/build/groff-1.25.0.rc1/build-64-clang/../src=
/preproc/tbl/main.cpp:270:4=0A    #6 0x590f76243bee in main =0A/build/groff=
-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:1782:5=0A    #7 0x73=
f1a782a600 in __libc_start_call_main =0Acsu/../sysdeps/nptl/libc_start_call=
_main.h:59:16=0A    #8 0x73f1a782a717 in __libc_start_main csu/../csu/libc-=
start.c:360:3=0A    #9 0x590f76142984 in _start =0A(/build/groff-1.25.0.rc1=
/build-64-clang/tbl+0x5e984)=0A=0ASUMMARY: AddressSanitizer: alloc-dealloc-=
mismatch =0A/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table=
.cpp:667:3 in =0Ablock_entry::~block_entry()=0A=3D=3D850834=3D=3DHINT: if y=
ou don't care about these errors you may set =0AASAN_OPTIONS=3Dalloc_deallo=
c_mismatch=3D0=0A=3D=3D850834=3D=3DABORTING=0A/build/groff-1.25.0.rc1/build=
-64-clang/groff: error: tbl: Aborted=0A=0AExplanation:=0Acalloc() pairs wit=
h free().=0Anew[] pairs with delete[].=0A=0ABruno=0A=0A=0A=0AI tried buildi=
ng the groff-1.25.0.rc1 with clang's ASAN.=0AThe next error (during "make -=
k check"):=0A=0A  GROFF    contrib/mom/examples/slide-demo.pdf=0A=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=0A=3D=3D851776=3D=3DERROR: AddressSani=
tizer: alloc-dealloc-mismatch (malloc vs operator=0A=0Adelete []) on 0x6d23=
571e0330=0A    #0 0x587f8b4ae9ed in operator delete[](void*) =0A/home/runne=
r/work/llvm-project/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:1=
79:46=0A    #1 0x587f8b4f8b0f in output::~output() =0A/build/groff-1.25.0.r=
c1/build-64-clang/../src/preproc/pic/object.cpp:47:3=0A    #2 0x587f8b5345a=
4 in common_output::~common_output() =0A/build/groff-1.25.0.rc1/build-64-cl=
ang/../src/preproc/pic/common.h:20:7=0A    #3 0x587f8b53c614 in simple_outp=
ut::~simple_output() =0A/build/groff-1.25.0.rc1/build-64-clang/../src/prepr=
oc/pic/troff.cpp:37:7=0A    #4 0x587f8b53757a in troff_output::~troff_outpu=
t() =0A/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/troff.cpp:=
276:1=0A    #5 0x587f8b5375d4 in troff_output::~troff_output() =0A/build/gr=
off-1.25.0.rc1/build-64-clang/../src/preproc/pic/troff.cpp:274:1=0A    #6 0=
x587f8b4f8423 in main =0A/build/groff-1.25.0.rc1/build-64-clang/../src/prep=
roc/pic/main.cpp:698:3=0A    #7 0x710357e2a600 in __libc_start_call_main =
=0Acsu/../sysdeps/nptl/libc_start_call_main.h:59:16=0A    #8 0x710357e2a717=
 in __libc_start_main csu/../csu/libc-start.c:360:3=0A    #9 0x587f8b3c5b04=
 in _start =0A(/build/groff-1.25.0.rc1/build-64-clang/pic+0x80b04)=0A=0A0x6=
d23571e0330 is located 0 bytes inside of 7-byte region =0A[0x6d23571e0330,0=
x6d23571e0337)=0Aallocated by thread T0 here:=0A    #0 0x587f8b46aee4 in ma=
lloc =0A/home/runner/work/llvm-project/llvm-project/compiler-rt/lib/asan/as=
an_malloc_linux.cpp:67:3=0A    #1 0x587f8b54c677 in strsave(char const*) =
=0A/build/groff-1.25.0.rc1/build-64-clang/../src/libs/libgroff/strsave.cpp:=
36:33=0A    #2 0x587f8b4f8d41 in output::set_args(char const*) =0A/build/gr=
off-1.25.0.rc1/build-64-clang/../src/preproc/pic/object.cpp:62:12=0A    #3 =
0x587f8b4f7356 in do_picture(_IO_FILE*) =0A/build/groff-1.25.0.rc1/build-64=
-clang/../src/preproc/pic/main.cpp:297:10=0A    #4 0x587f8b4f5f4f in do_fil=
e(char const*) =0A/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic=
/main.cpp:395:2=0A    #5 0x587f8b4f8241 in main =0A/build/groff-1.25.0.rc1/=
build-64-clang/../src/preproc/pic/main.cpp:691:7=0A    #6 0x710357e2a600 in=
 __libc_start_call_main =0Acsu/../sysdeps/nptl/libc_start_call_main.h:59:16=
=0A    #7 0x710357e2a717 in __libc_start_main csu/../csu/libc-start.c:360:3=
=0A    #8 0x587f8b3c5b04 in _start =0A(/build/groff-1.25.0.rc1/build-64-cla=
ng/pic+0x80b04)=0A=0ASUMMARY: AddressSanitizer: alloc-dealloc-mismatch =0A/=
build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/object.cpp:47:3 in=
 =0Aoutput::~output()=0A=3D=3D851776=3D=3DHINT: if you don't care about the=
se errors you may set =0AASAN_OPTIONS=3Dalloc_dealloc_mismatch=3D0=0A=3D=3D=
851776=3D=3DABORTING=0A/build/groff-1.25.0.rc1/build-64-clang/groff: error:=
 pic: Aborted=0A=0AExplanation:=0Amalloc() pairs with free().=0Anew[] pairs=
 with delete[].=0A=0ABruno=0A=0A=0AHowever, trying to resolve the _tbl_ iss=
ue pulled on a long thread of=0A`const`-incorrectness and an insufficiently=
 well documented internal API for=0A_libgroff_'s "string" class.=0A=0AWhile=
 eventually we can likely switch to C++ STL strings for everything=0Aoutsid=
e the formatter itself (_troff_), because we're handling character=0Asequen=
ces in a Unixy-way in those places, we'll need to retain the string=0Aclass=
--perhaps renamed "membuf" or something, because "characters" take on new=
=0Ameaning inside the formatter, and more importantly, we must deal with=0A=
sequences that have internal null bytes.  In a diversion, for example, a nu=
ll=0Abyte in its "macro_header"'s "char_list" indicates the presence of a=
=0Acorresponding "node" in the "node_list".=0A=0Ahttps://cgit.git.savannah.=
gnu.org/cgit/groff.git/tree/src/roff/troff/input.cpp?h=3D1.25.0.rc1#n4068=
=0A=0AThe=0A[https://www.gnu.org/software/groff/manual/groff.html.node/GNU-=
troff-Internals.html#GNU-troff-Internals=0A"GNU troff Internals" section of=
 groff's Texinfo manual also throws a little=0Alight on these matters].=0A=
=0AHere's a sketch of my current plan of attack:=0A=0A* Kill off straggling=
 uses of malloc()/calloc()/realloc()/free() in=0A_src/libs/libgroff/string.=
cpp_.=0A* string::contents() should return a `const char *`.=0A* string::ex=
tract() should return a `char *`.=0A* Neither function should worry about i=
nternal nulls; they should return a=0A`char` sequence up to the first null =
byte.  The return type will imply as much=0Ato any experienced C/C++ progra=
mmer anyway.=0A* Users of the `string` class that employ _either_ `contents=
()` or `extract()`=0Acan be flagged as potential migrants to the C++ standa=
rd `string` class.=0A=0AHere's a diff of how far I pulled the yarn before g=
iving up on trying to solve=0Athis problem for _groff_ 1.25.=0A=0A=0Adiff -=
-git a/src/devices/grops/ps.cpp b/src/devices/grops/ps.cpp=0Aindex d4aa564c=
8..8950f36db 100644=0A--- a/src/devices/grops/ps.cpp=0A+++ b/src/devices/gr=
ops/ps.cpp=0A@@ -906,7 +906,7 @@ void ps_printer::define_encoding(const cha=
r *encoding,=0A   int i;=0A   for (i =3D 0; i < 256; i++)=0A     vec[i] =3D=
 0;=0A-  char *path;=0A+  const char *path;=0A   if (strchr(encoding, '/') =
!=3D 0 /* nullptr */)=0A     fatal("a '/' is not allowed in encoding file n=
ame: '%1'", encoding);=0A   FILE *fp =3D font::open_file(encoding, &path);=
=0A@@ -942,7 +942,7 @@ void ps_printer::define_encoding(const char *encodin=
g,=0A     }=0A     lineno++;=0A   }=0A-  free(path);=0A+  free(const_cast<c=
har *>(path));=0A   out.put_literal_symbol(make_encoding_name(encoding_inde=
x))=0A      .put_delimiter('[');=0A   for (i =3D 0; i < 256; i++) {=0Adiff =
--git a/src/devices/grops/psrm.cpp b/src/devices/grops/psrm.cpp=0Aindex 6cc=
67ca36..106188f83 100644=0A--- a/src/devices/grops/psrm.cpp=0A+++ b/src/dev=
ices/grops/psrm.cpp=0A@@ -114,7 +114,7 @@ struct resource {=0A   unsigned f=
lags;=0A   string version;=0A   unsigned revision;=0A-  char *filename;=0A+=
  const char *filename;=0A   int rank;=0A   resource(resource_type, string =
&, string & =3D an_empty_string, unsigned =3D=0A0);=0A   ~resource();=0A@@ =
-130,13 +130,13 @@ resource::resource(resource_type t, string &n, string=0A=
&v, unsigned r)=0A   if (type =3D=3D RESOURCE_FILE) {=0A     if (name.searc=
h('\0') >=3D 0)=0A       error("file name contains character code 0");=0A- =
   filename =3D name.extract();=0A+    filename =3D name.contents();=0A   }=
=0A }=0A =0A resource::~resource()=0A {=0A-  free(filename);=0A+  free(cons=
t_cast<char *>(filename));=0A }=0A =0A void resource::print_type_and_name(F=
ILE *outfp)=0A@@ -323,7 +323,7 @@ void resource_manager::output_prolog(ps_o=
utput &out)=0A {=0A   FILE *outfp =3D out.get_file();=0A   out.end_line();=
=0A-  char *path;=0A+  const char *path;=0A   if (getenv("GROPS_PROLOGUE") =
=3D=3D 0 /* nullptr */) {=0A     if (setenv("GROPS_PROLOGUE", GROPS_PROLOGU=
E, 1 /* overwrite */)=0A        !=3D 0)=0A@@ -342,7 +342,7 @@ void resource=
_manager::output_prolog(ps_output &out)=0A   putc('\n', outfp);=0A   proces=
s_file(-1, fp, path, outfp);=0A   fclose(fp);=0A-  free(path);=0A+  free(co=
nst_cast<char *>(path));=0A   fputs("%%EndResource\n", outfp);=0A }=0A =0A@=
@ -366,7 +366,7 @@ void resource_manager::supply_resource(resource *r, int=
=0Arank,=0A   r->flags |=3D resource::BUSY;=0A   if (rank > r->rank)=0A    =
 r->rank =3D rank;=0A-  char *path =3D 0 /* nullptr */;=0A+  const char *pa=
th =3D 0 /* nullptr */;=0A   FILE *fp =3D 0 /* nullptr */;=0A   if (r->file=
name !=3D 0 /* nullptr */) {=0A     if (r->type =3D=3D RESOURCE_FONT) {=0A@=
@ -406,7 +406,7 @@ void resource_manager::supply_resource(resource *r, int=
=0Arank,=0A     process_file(rank, fp, path, outfp);=0A     fclose(fp);=0A =
    if (r->type =3D=3D RESOURCE_FONT)=0A-      free(path);=0A+      free(co=
nst_cast<char *>(path));=0A     if (outfp) {=0A       if (r->type =3D=3D RE=
SOURCE_FILE && is_document)=0A        fputs("%%EndDocument\n", outfp);=0A@@=
 -1098,7 +1098,7 @@ void resource_manager::process_file(int rank, FILE *fp,=
=0A =0A void resource_manager::read_download_file()=0A {=0A-  char *path =
=3D 0 /* nullptr */;=0A+  const char *path =3D 0 /* nullptr */;=0A   FILE *=
fp =3D font::open_file("download", &path);=0A   if (0 /* nullptr */ =3D=3D =
fp)=0A     fatal("cannot open 'download' file: %1", strerror(errno));=0A@@ =
-1115,7 +1115,7 @@ void resource_manager::read_download_file()=0A          =
                     " font '%1'", p);=0A     lookup_font(p)->filename =3D =
strsave(q);=0A   }=0A-  free(path);=0A+  free(const_cast<char *>(path));=0A=
   fclose(fp);=0A }=0A =0Adiff --git a/src/include/font.h b/src/include/fon=
t.h=0Aindex 85bae6719..39dd33c4b 100644=0A--- a/src/include/font.h=0A+++ b/=
src/include/font.h=0A@@ -218,7 +218,7 @@ public:=0A   static void command_l=
ine_font_dir(const char *);     // Prepend given=0A                        =
// path (arg1) to the list of directories in which=0A                      =
  // to look up fonts.=0A-  static FILE *open_file(const char *, char **); =
// Open a font=0A+  static FILE *open_file(const char *, const char **); //=
 Open a font=0A                        // description file with the given n=
ame (arg1),=0A                        // searching along the current font p=
ath, and=0A                        // rejecting `arg1` if it contains a sla=
sh (see=0A@@ -228,10 +228,10 @@ public:=0A                        // opened=
 file's stream pointer.  If not found,=0A                        // arg2 is=
 unchanged, and a null pointer is=0A                        // returned.=0A=
-  static FILE *open_resource_file(const char *, char **); // Open an=0A-  =
                     // externally supplied (non-groff) file required=0A-  =
                     // by the output driver, possibly to embed=0A-        =
               // content in the generated file.  Like=0A+  static FILE *op=
en_resource_file(const char *, const char **); // Open=0A+                 =
      // an externally supplied (non-groff) file=0A+                       =
// required by the output driver, possibly to=0A+                       // =
embed content in the generated file.  Like=0A                        // `op=
en_file()` except that it accepts slashes=0A                        // in `=
arg1`.  Examples include Type 1 fonts=0A                        // embedded=
 in PostScript output.=0Adiff --git a/src/include/searchpath.h b/src/includ=
e/searchpath.h=0Aindex 65b94e8a0..af7c28298 100644=0A--- a/src/include/sear=
chpath.h=0A+++ b/src/include/searchpath.h=0A@@ -25,8 +25,9 @@ public:=0A   =
           int add_home, int add_current);=0A   ~search_path();=0A   void c=
ommand_line_dir(const char *);=0A-  FILE *open_file(const char *, char **);=
=0A-  FILE *open_file_cautiously(const char *, char ** =3D 0 /* nullptr */,=
=0A+  FILE *open_file(const char *, const char **);=0A+  FILE *open_file_ca=
utiously(const char *,=0A+                            const char ** =3D 0 /=
* nullptr */,=0A                             const char * =3D 0 /* nullptr =
*/);=0A };=0A =0Adiff --git a/src/include/stringclass.h b/src/include/strin=
gclass.h=0Aindex 131c13718..f3736ddba 100644=0A--- a/src/include/stringclas=
s.h=0A+++ b/src/include/stringclass.h=0A@@ -76,7 +76,7 @@ public:=0A   int =
search(const char) const;=0A   bool contains(const char) const;=0A   ssize_=
t find(const char *) const;=0A-  char *extract() const;=0A+  const char *ex=
tract() const;=0A   size_t json_length() const;=0A   const char *json_extra=
ct() const;=0A   void json_dump() const;=0Adiff --git a/src/libs/libgroff/f=
ont.cpp b/src/libs/libgroff/font.cpp=0Aindex 362abf527..b6c1886e7 100644=0A=
--- a/src/libs/libgroff/font.cpp=0A+++ b/src/libs/libgroff/font.cpp=0A@@ -7=
9,13 +79,13 @@ struct font_widths_cache {=0A =0A struct text_file {=0A   FI=
LE *fp;=0A-  char *path;=0A+  const char *path;=0A   int lineno;=0A   int l=
inebufsize;=0A   bool recognize_comments;=0A   bool silent;=0A   char *buf;=
=0A-  text_file(FILE *fp, char *p);=0A+  text_file(FILE *fp, const char *p)=
;=0A   ~text_file();=0A   bool next_line();=0A   void error(const char *for=
mat,=0A@@ -98,8 +98,8 @@ struct text_file {=0A             const errarg &ar=
g3 =3D empty_errarg);=0A };=0A =0A-text_file::text_file(FILE *p, char *s) :=
 fp(p), path(s), lineno(0),=0A-  linebufsize(128), recognize_comments(true)=
, silent(false),=0A+text_file::text_file(FILE *p, const char *s) : fp(p), p=
ath(s),=0A+  lineno(0), linebufsize(128), recognize_comments(true), silent(=
false),=0A   buf(0 /* nullptr */)=0A {=0A }=0A@@ -107,7 +107,7 @@ text_file=
::text_file(FILE *p, char *s) : fp(p), path(s),=0Alineno(0),=0A text_file::=
~text_file()=0A {=0A   delete[] buf;=0A-  free(path);=0A+  free(const_cast<=
char *>(path));=0A   if (fp)=0A     fclose(fp);=0A }=0A@@ -898,7 +898,7 @@ =
again:=0A =0A bool font::load(bool want_diagnostic, bool validate_only)=0A =
{=0A-  char *path;=0A+  const char *path;=0A   FILE *fp =3D open_file(filen=
ame, &path);=0A   if (0 /* nullptr */ =3D=3D fp) {=0A     if (want_diagnost=
ic)=0A@@ -1284,7 +1284,7 @@ static struct numeric_directive {=0A const char=
 *font::load_desc()=0A {=0A   int nfonts =3D 0;=0A-  char *path;=0A+  const=
 char *path;=0A   FILE *fp =3D open_file("DESC", &path);=0A   if (0 /* null=
ptr */ =3D=3D fp)=0A     return 0 /* nullptr */;=0Adiff --git a/src/libs/li=
bgroff/fontfile.cpp b/src/libs/libgroff/fontfile.cpp=0Aindex 148fd3be3..133=
66eae6 100644=0A--- a/src/libs/libgroff/fontfile.cpp=0A+++ b/src/libs/libgr=
off/fontfile.cpp=0A@@ -64,7 +64,7 @@ void font::command_line_font_dir(const=
 char *dir)=0A   font_path.command_line_dir(dir);=0A }=0A =0A-FILE *font::o=
pen_file(const char *nm, char **pathp)=0A+FILE *font::open_file(const char =
*nm, const char **pathp)=0A {=0A   assert(nm !=3D 0 /* nullptr */);=0A   as=
sert(device !=3D 0 /* nullptr */);=0A@@ -85,7 +85,7 @@ FILE *font::open_fil=
e(const char *nm, char **pathp)=0A   return fp;=0A }=0A =0A-FILE *font::ope=
n_resource_file(const char *nm, char **pathp)=0A+FILE *font::open_resource_=
file(const char *nm, const char **pathp)=0A {=0A   assert(nm !=3D 0 /* null=
ptr */);=0A   assert(device !=3D 0 /* nullptr */);=0Adiff --git a/src/libs/=
libgroff/searchpath.cpp=0Ab/src/libs/libgroff/searchpath.cpp=0Aindex 3ad25a=
704..4ed59b0d5 100644=0A--- a/src/libs/libgroff/searchpath.cpp=0A+++ b/src/=
libs/libgroff/searchpath.cpp=0A@@ -113,7 +113,7 @@ void search_path::comman=
d_line_dir(const char *s)=0A   delete[] old;=0A }=0A =0A-FILE *search_path:=
:open_file(const char *name, char **pathp)=0A+FILE *search_path::open_file(=
const char *name, const char **pathp)=0A {=0A   assert(name !=3D 0 /* nullp=
tr */);=0A   if (IS_ABSOLUTE(name) || *dirs =3D=3D '\0') {=0A@@ -174,7 +174=
,8 @@ FILE *search_path::open_file(const char *name, char=0A**pathp)=0A   r=
eturn 0 /* nullptr */;=0A }=0A =0A-FILE *search_path::open_file_cautiously(=
const char *name, char **pathp,=0A+FILE *search_path::open_file_cautiously(=
const char *name,=0A+                                       const char **pa=
thp,=0A                                        const char *mode)=0A {=0A   =
if (0 /* nullptr */ =3D=3D mode)=0Adiff --git a/src/libs/libgroff/string.cp=
p b/src/libs/libgroff/string.cpp=0Aindex eb01c3078..0fb810dbd 100644=0A--- =
a/src/libs/libgroff/string.cpp=0A+++ b/src/libs/libgroff/string.cpp=0A@@ -3=
72,7 +372,7 @@ ssize_t string::find(const char *c) const=0A // Return point=
er to null-terminated C string; any nulls internal to the=0A // string are =
omitted.  The caller is responsible for `free()`ing the=0A // returned stor=
age.=0A-char *string::extract() const=0A+const char *string::extract() cons=
t=0A {=0A   char *p =3D ptr;=0A   size_t n =3D len;=0A@@ -381,15 +381,18 @@=
 char *string::extract() const=0A   for (i =3D 0; i < n; i++)=0A     if (p[=
i] =3D=3D '\0')=0A       nnuls++;=0A-  char *q =3D static_cast<char *>(call=
oc(n + 1 - nnuls, sizeof(char)));=0A+  size_t extracted_length =3D n + 1 /*=
 '\0' */ - nnuls;=0A+  //char *q =3D static_cast<char *>(calloc(n + 1 - nnu=
ls, sizeof(char)));=0A+  string *q =3D new string;=0A+  //(void) memset(q, =
0, extracted_length);=0A   if (q !=3D 0 /* nullptr */) {=0A-    char *r =3D=
 q;=0A+    q->set_length(extracted_length);=0A     for (i =3D 0; i < n; i++=
)=0A       if (p[i] !=3D '\0')=0A-       *r++ =3D p[i];=0A-    *r =3D '\0';=
=0A+       *q++ =3D p[i];=0A+    *q =3D '\0';=0A   }=0A-  return q;=0A+  re=
turn q->contents();=0A }=0A =0A // Compute length of JSON representation of=
 object.=0Adiff --git a/src/preproc/eqn/main.cpp b/src/preproc/eqn/main.cpp=
=0Aindex 2574f7d37..a9ac291a5 100644=0A--- a/src/preproc/eqn/main.cpp=0A+++=
 b/src/preproc/eqn/main.cpp=0A@@ -467,13 +467,13 @@ int main(int argc, char=
 **argv)=0A           " 'groff -Thtml -e')\n", device);=0A   }=0A   if (wan=
t_startup_file) {=0A-    char *path;=0A+    const char *path;=0A     FILE *=
fp =3D config_macro_path.open_file(STARTUP_FILE, &path);=0A     if (fp !=3D=
 0 /* nullptr */) {=0A       do_file(fp, path);=0A       if (fclose(fp) < 0=
)=0A        fatal("cannot close '%1': %2", STARTUP_FILE, strerror(errno));=
=0A-      free(path);=0A+      free(const_cast<char *>(path));=0A     }=0A =
    else=0A       error("cannot open startup file '%1': %2", STARTUP_FILE,=
=0Adiff --git a/src/preproc/grn/main.cpp b/src/preproc/grn/main.cpp=0Aindex=
 dc2835f0e..773c611dd 100644=0A--- a/src/preproc/grn/main.cpp=0A+++ b/src/p=
reproc/grn/main.cpp=0A@@ -577,7 +577,7 @@ conv(FILE *fp,=0A          error(=
"no picture file name at line %1", baseline);=0A        return;=0A       }=
=0A-      char *path;=0A+      const char *path;=0A       gfp =3D macro_pat=
h.open_file(gremlinfile, &path);=0A       if (0 /* nullptr */ =3D=3D gfp) {=
=0A        error("cannot open picture file '%1': %2", gremlinfile,=0A@@ -58=
6,7 +586,7 @@ conv(FILE *fp,=0A       }=0A       PICTURE =3D DBRead(gfp);  =
 /* read picture file */=0A       fclose(gfp);=0A-      free(path);=0A+    =
  free(const_cast<char *>(path));=0A       if (DBNullelt(PICTURE))=0A      =
  return;                 /* If a request is made to make the  */=0A       =
                         /* picture fit into a specific area, */=0Adiff --g=
it a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp=0Aindex =
7b6993db2..e9c87c52d 100644=0A--- a/src/preproc/html/pre-html.cpp=0A+++ b/s=
rc/preproc/html/pre-html.cpp=0A@@ -330,7 +330,7 @@ static bool get_line(FIL=
E *f, const char *file_name, int=0Alineno)=0A =0A static unsigned int get_r=
esolution(void)=0A {=0A-  char *pathp;=0A+  const char *pathp;=0A   FILE *f=
;=0A   unsigned int res =3D 0;=0A   f =3D font_path.open_file(devps_desc, &=
pathp);=0A@@ -347,7 +347,7 @@ static unsigned int get_resolution(void)=0A  =
      break;=0A     }=0A   }=0A-  free(pathp);=0A+  free(const_cast<char *>=
(pathp));=0A   fclose(f);=0A   return res;=0A }=0A@@ -360,7 +360,7 @@ stati=
c unsigned int get_resolution(void)=0A =0A static char *get_image_generator=
(void)=0A {=0A-  char *pathp;=0A+  const char *pathp;=0A   FILE *f;=0A   ch=
ar *generator =3D 0 /* nullptr */;=0A   const char keyword[] =3D "image_gen=
erator";=0A@@ -393,7 +393,7 @@ static char *get_image_generator(void)=0A   =
     break;=0A     }=0A   }=0A-  free(pathp);=0A+  free(const_cast<char *>(=
pathp));=0A   fclose(f);=0A   return generator;=0A }=0Adiff --git a/src/pre=
proc/preconv/preconv.cpp=0Ab/src/preproc/preconv/preconv.cpp=0Aindex cd13b5=
070..fdd74de9d 100644=0A--- a/src/preproc/preconv/preconv.cpp=0A+++ b/src/p=
reproc/preconv/preconv.cpp=0A@@ -885,14 +885,18 @@ get_tag_lines(FILE *fp, =
string &data)=0A        data +=3D char(c);=0A     }=0A   }=0A-  return data=
.extract();=0A+  // We need a mutable string.=0A+  const char *tag_lines_co=
nst =3D data.extract();=0A+  char *tag_lines =3D strdup(tag_lines_const); /=
/ XXX: leaky=0A+  free(const_cast<char *>(tag_lines_const));=0A+  return ta=
g_lines;=0A }=0A =0A // ---------------------------------------------------=
------=0A // Indicate whether C string starts with a comment.=0A // -------=
--------------------------------------------------=0A static bool=0A-is_com=
ment_line(char *s)=0A+is_comment_line(const char *s)=0A {=0A   if (!s || !*=
s)=0A     return false;=0A@@ -1128,17 +1132,17 @@ do_file(const char *filen=
ame)=0A     fp =3D fopen(filename, FOPEN_RB);=0A     reported_filename =3D =
"'" + string(filename) + "'";=0A   }=0A-  char *c_reported_filename =3D rep=
orted_filename.extract();=0A+  const char *c_reported_filename =3D reported=
_filename.extract();=0A   if (!fp) {=0A     error("cannot open %1: %2", c_r=
eported_filename, strerror(errno));=0A-    free(c_reported_filename);=0A+  =
  free(const_cast<char *>(c_reported_filename));=0A     return false;=0A   =
}=0A   if (is_debugging) {=0A     fprintf(stderr, "processing %s\n", c_repo=
rted_filename);=0A     fflush(stderr);=0A   }=0A-  free(c_reported_filename=
);=0A+  free(const_cast<char *>(c_reported_filename));=0A   if (fseek(fp, 0=
L, SEEK_SET) =3D=3D 0)=0A     is_seekable =3D true;=0A   else {=0Adiff --gi=
t a/src/preproc/soelim/soelim.cpp b/src/preproc/soelim/soelim.cpp=0Aindex 1=
064edaef..68a61bb3f 100644=0A--- a/src/preproc/soelim/soelim.cpp=0A+++ b/sr=
c/preproc/soelim/soelim.cpp=0A@@ -194,7 +194,7 @@ static void do_so(const c=
har *line)=0A =0A static bool do_file(const char *filename)=0A {=0A-  char =
*file_name_in_path =3D 0 /* nullptr */;=0A+  const char *file_name_in_path =
=3D 0 /* nullptr */;=0A   FILE *fp =3D include_search_path.open_file_cautio=
usly(filename,=0A       &file_name_in_path);=0A   int err =3D errno;=0A@@ -=
202,7 +202,7 @@ static bool do_file(const char *filename)=0A   if (strcmp(f=
ilename, "-") && file_name_in_path !=3D 0 /* nullptr */)=0A     whole_filen=
ame =3D file_name_in_path;=0A   whole_filename +=3D '\0';=0A-  free(file_na=
me_in_path);=0A+  free(const_cast<char *>(file_name_in_path));=0A   if (0 /=
* nullptr */ =3D=3D fp) {=0A     error("cannot open '%1': %2", whole_filena=
me.contents(),=0A          strerror(err));=0Adiff --git a/src/preproc/tbl/t=
able.cpp b/src/preproc/tbl/table.cpp=0Aindex bd0abcda6..6b085bf77 100644=0A=
--- a/src/preproc/tbl/table.cpp=0A+++ b/src/preproc/tbl/table.cpp=0A@@ -154=
3,7 +1543,9 @@ void table::add_entry(int r, int c, const string &str,=0A   =
allocate(r);=0A   table_entry *e =3D 0 /* nullptr */;=0A   ssize_t len =3D =
str.length();=0A-  char *s =3D str.extract();=0A+  const char *s_const =3D =
str.extract();=0A+  // We need a mutable string.=0A+  char *s =3D strdup(s_=
const); // XXX: leaky=0A   // Diagnose escape sequences that can wreak havo=
c in generated output.=0A   if (len > 1) {=0A     // A comment on a control=
 line or in a text block is okay.=0A@@ -1648,7 +1650,9 @@ void table::add_e=
ntry(int r, int c, const string &str,=0A       e =3D new empty_entry(this, =
f);=0A     }=0A     else {=0A-      char *glyph =3D str.substring(2, len - =
2).extract();=0A+      const char *glyph_const =3D str.substring(2, len - 2=
).extract();=0A+      // We need a mutable string.=0A+      char *glyph =3D=
 strdup(glyph_const); // XXX: leaky=0A       e =3D new repeated_char_entry(=
this, f, glyph);=0A     }=0A   }=0Adiff --git a/src/roff/troff/env.cpp b/sr=
c/roff/troff/env.cpp=0Aindex 8f4542d89..a71ed55ea 100644=0A--- a/src/roff/t=
roff/env.cpp=0A+++ b/src/roff/troff/env.cpp=0A@@ -4454,7 +4454,7 @@ void hy=
phen_trie::interpret_patterns_file(const char=0A*name,=0A     buf[i] =3D 0;=
=0A   int num[WORD_MAX + 1];=0A   errno =3D 0;=0A-  char *path =3D 0;=0A+  =
const char *path =3D 0;=0A   FILE *fp =3D mac_path->open_file(name, &path);=
=0A   if (0 /* nullptr */ =3D=3D fp) {=0A     error("cannot open hyphenatio=
n pattern file '%1': %2", name,=0A@@ -4582,7 +4582,7 @@ void hyphen_trie::i=
nterpret_patterns_file(const char=0A*name,=0A     }=0A   }=0A   fclose(fp);=
=0A-  free(path);=0A+  free(const_cast<char *>(path));=0A   return;=0A }=0A=
 =0Adiff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp=0Ainde=
x c9e6be2ac..8b6ae00e3 100644=0A--- a/src/roff/troff/input.cpp=0A+++ b/src/=
roff/troff/input.cpp=0A@@ -9831,7 +9831,7 @@ static void parse_output_page_=
list(const char *p)=0A   }=0A }=0A =0A-static FILE *open_macro_package(cons=
t char *mac, char **path)=0A+static FILE *open_macro_package(const char *ma=
c, const char **path)=0A {=0A   // Try `mac`.tmac first, then tmac.`mac`.  =
Expect ENOENT errors.=0A   // ISO C++ does not permit VLAs on the stack.=0A=
@@ -9863,13 +9863,13 @@ static FILE *open_macro_package(const char *mac, ch=
ar=0A**path)=0A =0A static void process_macro_package_argument(const char *=
mac)=0A {=0A-  char *path;=0A+  const char *path;=0A   FILE *fp =3D open_ma=
cro_package(mac, &path);=0A   if (0 /* nullptr */ =3D=3D fp)=0A     fatal("=
cannot open macro file named in '-m' command-line argument"=0A          " '=
%1': %2", mac, strerror(errno));=0A   const char *s =3D symbol(path).conten=
ts();=0A-  free(path);=0A+  free(const_cast<char *>(path));=0A   input_stac=
k::push(new file_iterator(fp, s));=0A   tok.next();=0A   process_input_stac=
k();=0A@@ -9877,13 +9877,13 @@ static void process_macro_package_argument(c=
onst char=0A*mac)=0A =0A static void process_startup_file(const char *filen=
ame)=0A {=0A-  char *path;=0A+  const char *path;=0A   search_path *orig_ma=
c_path =3D mac_path;=0A   mac_path =3D &config_macro_path;=0A   FILE *fp =
=3D mac_path->open_file(filename, &path);=0A   if (fp !=3D 0 /* nullptr */)=
 {=0A     input_stack::push(new file_iterator(fp, symbol(path).contents()))=
;=0A-    free(path);=0A+    free(const_cast<char *>(path));=0A     tok.next=
();=0A     process_input_stack();=0A   }=0A@@ -9896,11 +9896,11 @@ static v=
oid process_startup_file(const char=0A*filename)=0A static void do_macro_so=
urce(bool quietly)=0A {=0A   char *macro_filename =3D read_rest_of_line_as_=
argument();=0A-  char *path;=0A+  const char *path;=0A   FILE *fp =3D mac_p=
ath->open_file(macro_filename, &path);=0A   if (fp !=3D 0 /* nullptr */) {=
=0A     input_stack::push(new file_iterator(fp, macro_filename));=0A-    fr=
ee(path);=0A+    free(const_cast<char *>(path));=0A   }=0A   else=0A     //=
 Suppress diagnostic only if we're operating quietly and it's an=0A=0A=0A=
=0A=0A=0A=0A=0A=0A=0A=0A    _______________________________________________=
________=0A=0AReply to this item at:=0A=0A  <https://savannah.gnu.org/bugs/=
?68585>=0A=0A_______________________________________________=0AMessage sent=
 via Savannah=0Ahttps://savannah.gnu.org/=0A
--8323329-1714636915-1785527596=:2042551
Content-Type: APPLICATION/pgp-signature; name=signature.asc

-----BEGIN PGP SIGNATURE-----

iHUEABYIAB0WIQQk97aszIMMAvLLwm6qLAuaBUf3TgUCamz9LAAKCRCqLAuaBUf3
Tt3+AP0bE1fxOjXNb5lhbxYY5HJV5YMcKzK8+CyRyKQNs/kmjAD/eKU4gtyp/Fl+
lERZFPRaKRjtG7r+rx13mtUMJI0CRQk=
=xTnh
-----END PGP SIGNATURE-----

--8323329-1714636915-1785527596=:2042551--