URL:
  <https://savannah.gnu.org/bugs/?68585>

                 Summary: [pic,tbl] code not
"ASAN_OPTIONS=alloc_dealloc_mismatch=1" clean
                   Group: GNU roff
               Submitter: gbranden
               Submitted: Fri 31 Jul 2026 07:53:12 PM UTC
                Category: Preprocessor - others/general
                Severity: 3 - Normal
              Item Group: Incorrect behaviour
                  Status: Confirmed
                 Privacy: Public
             Assigned to: None
             Open/Closed: Open
         Discussion Lock: Unlocked
         Planned Release: None


    _______________________________________________________

Follow-up Comments:


-------------------------------------------------------
Date: Fri 31 Jul 2026 07:53:12 PM UTC By: G. Branden Robinson <gbranden>
Bruno reported [https://lists.gnu.org/archive/html/groff/2026-07/msg00055.html
these] [https://lists.gnu.org/archive/html/groff/2026-07/msg00057.html issues]
to the _groff_ list.


I tried building the groff-1.25.0.rc1 with clang's ASAN.
The next error (during "make -k check"):

  GROFF    doc/groff-man-pages.pdf
=================================================================
==850834==ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator

delete []) on 0x7051a6beb4e0
    #0 0x590f7622b86d in operator delete[](void*) 
/home/runner/work/llvm-project/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:179:46
    #1 0x590f7624cdff in block_entry::~block_entry() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:667:3
    #2 0x590f76282a24 in left_block_entry::~left_block_entry() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:334:7
    #3 0x590f76282a74 in left_block_entry::~left_block_entry() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:334:7
    #4 0x590f7625ce86 in table::~table() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:1309:5
    #5 0x590f7622e9fc in process_table(table_input&) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:1667:5
    #6 0x590f7622dda7 in process_input_file(_IO_FILE*) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:270:4
    #7 0x590f76243bee in main 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:1782:5
    #8 0x73f1a782a600 in __libc_start_call_main 
csu/../sysdeps/nptl/libc_start_call_main.h:59:16
    #9 0x73f1a782a717 in __libc_start_main csu/../csu/libc-start.c:360:3
    #10 0x590f76142984 in _start 
(/build/groff-1.25.0.rc1/build-64-clang/tbl+0x5e984)

0x7051a6beb4e0 is located 0 bytes inside of 62-byte region 
[0x7051a6beb4e0,0x7051a6beb51e)
allocated by thread T0 here:
    #0 0x590f761e7f39 in calloc 
/home/runner/work/llvm-project/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:74:3
    #1 0x590f7628be7a in string::extract() const 
/build/groff-1.25.0.rc1/build-64-clang/../src/libs/libgroff/string.cpp:384:33
    #2 0x590f76263398 in table::add_entry(int, int, string const&,
entry_format 
const*, char const*, int) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:1545:17
    #3 0x590f76240b46 in process_data(table_input&, format*, options*) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:1567:13
    #4 0x590f7622e972 in process_table(table_input&) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:1665:17
    #5 0x590f7622dda7 in process_input_file(_IO_FILE*) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:270:4
    #6 0x590f76243bee in main 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/main.cpp:1782:5
    #7 0x73f1a782a600 in __libc_start_call_main 
csu/../sysdeps/nptl/libc_start_call_main.h:59:16
    #8 0x73f1a782a717 in __libc_start_main csu/../csu/libc-start.c:360:3
    #9 0x590f76142984 in _start 
(/build/groff-1.25.0.rc1/build-64-clang/tbl+0x5e984)

SUMMARY: AddressSanitizer: alloc-dealloc-mismatch 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/tbl/table.cpp:667:3 in 
block_entry::~block_entry()
==850834==HINT: if you don't care about these errors you may set 
ASAN_OPTIONS=alloc_dealloc_mismatch=0
==850834==ABORTING
/build/groff-1.25.0.rc1/build-64-clang/groff: error: tbl: Aborted

Explanation:
calloc() pairs with free().
new[] pairs with delete[].

Bruno



I tried building the groff-1.25.0.rc1 with clang's ASAN.
The next error (during "make -k check"):

  GROFF    contrib/mom/examples/slide-demo.pdf
=================================================================
==851776==ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator

delete []) on 0x6d23571e0330
    #0 0x587f8b4ae9ed in operator delete[](void*) 
/home/runner/work/llvm-project/llvm-project/compiler-rt/lib/asan/asan_new_delete.cpp:179:46
    #1 0x587f8b4f8b0f in output::~output() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/object.cpp:47:3
    #2 0x587f8b5345a4 in common_output::~common_output() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/common.h:20:7
    #3 0x587f8b53c614 in simple_output::~simple_output() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/troff.cpp:37:7
    #4 0x587f8b53757a in troff_output::~troff_output() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/troff.cpp:276:1
    #5 0x587f8b5375d4 in troff_output::~troff_output() 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/troff.cpp:274:1
    #6 0x587f8b4f8423 in main 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/main.cpp:698:3
    #7 0x710357e2a600 in __libc_start_call_main 
csu/../sysdeps/nptl/libc_start_call_main.h:59:16
    #8 0x710357e2a717 in __libc_start_main csu/../csu/libc-start.c:360:3
    #9 0x587f8b3c5b04 in _start 
(/build/groff-1.25.0.rc1/build-64-clang/pic+0x80b04)

0x6d23571e0330 is located 0 bytes inside of 7-byte region 
[0x6d23571e0330,0x6d23571e0337)
allocated by thread T0 here:
    #0 0x587f8b46aee4 in malloc 
/home/runner/work/llvm-project/llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:67:3
    #1 0x587f8b54c677 in strsave(char const*) 
/build/groff-1.25.0.rc1/build-64-clang/../src/libs/libgroff/strsave.cpp:36:33
    #2 0x587f8b4f8d41 in output::set_args(char const*) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/object.cpp:62:12
    #3 0x587f8b4f7356 in do_picture(_IO_FILE*) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/main.cpp:297:10
    #4 0x587f8b4f5f4f in do_file(char const*) 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/main.cpp:395:2
    #5 0x587f8b4f8241 in main 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/main.cpp:691:7
    #6 0x710357e2a600 in __libc_start_call_main 
csu/../sysdeps/nptl/libc_start_call_main.h:59:16
    #7 0x710357e2a717 in __libc_start_main csu/../csu/libc-start.c:360:3
    #8 0x587f8b3c5b04 in _start 
(/build/groff-1.25.0.rc1/build-64-clang/pic+0x80b04)

SUMMARY: AddressSanitizer: alloc-dealloc-mismatch 
/build/groff-1.25.0.rc1/build-64-clang/../src/preproc/pic/object.cpp:47:3 in 
output::~output()
==851776==HINT: if you don't care about these errors you may set 
ASAN_OPTIONS=alloc_dealloc_mismatch=0
==851776==ABORTING
/build/groff-1.25.0.rc1/build-64-clang/groff: error: pic: Aborted

Explanation:
malloc() pairs with free().
new[] pairs with delete[].

Bruno


However, trying to resolve the _tbl_ issue pulled on a long thread of
`const`-incorrectness and an insufficiently well documented internal API for
_libgroff_'s "string" class.

While eventually we can likely switch to C++ STL strings for everything
outside the formatter itself (_troff_), because we're handling character
sequences in a Unixy-way in those places, we'll need to retain the string
class--perhaps renamed "membuf" or something, because "characters" take on new
meaning inside the formatter, and more importantly, we must deal with
sequences that have internal null bytes.  In a diversion, for example, a null
byte in its "macro_header"'s "char_list" indicates the presence of a
corresponding "node" in the "node_list".

https://cgit.git.savannah.gnu.org/cgit/groff.git/tree/src/roff/troff/input.cpp?h=1.25.0.rc1#n4068

The
[https://www.gnu.org/software/groff/manual/groff.html.node/GNU-troff-Internals.html#GNU-troff-Internals
"GNU troff Internals" section of groff's Texinfo manual also throws a little
light on these matters].

Here's a sketch of my current plan of attack:

* Kill off straggling uses of malloc()/calloc()/realloc()/free() in
_src/libs/libgroff/string.cpp_.
* string::contents() should return a `const char *`.
* string::extract() should return a `char *`.
* Neither function should worry about internal nulls; they should return a
`char` sequence up to the first null byte.  The return type will imply as much
to any experienced C/C++ programmer anyway.
* Users of the `string` class that employ _either_ `contents()` or `extract()`
can be flagged as potential migrants to the C++ standard `string` class.

Here's a diff of how far I pulled the yarn before giving up on trying to solve
this problem for _groff_ 1.25.


diff --git a/src/devices/grops/ps.cpp b/src/devices/grops/ps.cpp
index d4aa564c8..8950f36db 100644
--- a/src/devices/grops/ps.cpp
+++ b/src/devices/grops/ps.cpp
@@ -906,7 +906,7 @@ void ps_printer::define_encoding(const char *encoding,
   int i;
   for (i = 0; i < 256; i++)
     vec[i] = 0;
-  char *path;
+  const char *path;
   if (strchr(encoding, '/') != 0 /* nullptr */)
     fatal("a '/' is not allowed in encoding file name: '%1'", encoding);
   FILE *fp = font::open_file(encoding, &path);
@@ -942,7 +942,7 @@ void ps_printer::define_encoding(const char *encoding,
     }
     lineno++;
   }
-  free(path);
+  free(const_cast<char *>(path));
   out.put_literal_symbol(make_encoding_name(encoding_index))
      .put_delimiter('[');
   for (i = 0; i < 256; i++) {
diff --git a/src/devices/grops/psrm.cpp b/src/devices/grops/psrm.cpp
index 6cc67ca36..106188f83 100644
--- a/src/devices/grops/psrm.cpp
+++ b/src/devices/grops/psrm.cpp
@@ -114,7 +114,7 @@ struct resource {
   unsigned flags;
   string version;
   unsigned revision;
-  char *filename;
+  const char *filename;
   int rank;
   resource(resource_type, string &, string & = an_empty_string, unsigned =
0);
   ~resource();
@@ -130,13 +130,13 @@ resource::resource(resource_type t, string &n, string
&v, unsigned r)
   if (type == RESOURCE_FILE) {
     if (name.search('\0') >= 0)
       error("file name contains character code 0");
-    filename = name.extract();
+    filename = name.contents();
   }
 }
 
 resource::~resource()
 {
-  free(filename);
+  free(const_cast<char *>(filename));
 }
 
 void resource::print_type_and_name(FILE *outfp)
@@ -323,7 +323,7 @@ void resource_manager::output_prolog(ps_output &out)
 {
   FILE *outfp = out.get_file();
   out.end_line();
-  char *path;
+  const char *path;
   if (getenv("GROPS_PROLOGUE") == 0 /* nullptr */) {
     if (setenv("GROPS_PROLOGUE", GROPS_PROLOGUE, 1 /* overwrite */)
        != 0)
@@ -342,7 +342,7 @@ void resource_manager::output_prolog(ps_output &out)
   putc('\n', outfp);
   process_file(-1, fp, path, outfp);
   fclose(fp);
-  free(path);
+  free(const_cast<char *>(path));
   fputs("%%EndResource\n", outfp);
 }
 
@@ -366,7 +366,7 @@ void resource_manager::supply_resource(resource *r, int
rank,
   r->flags |= resource::BUSY;
   if (rank > r->rank)
     r->rank = rank;
-  char *path = 0 /* nullptr */;
+  const char *path = 0 /* nullptr */;
   FILE *fp = 0 /* nullptr */;
   if (r->filename != 0 /* nullptr */) {
     if (r->type == RESOURCE_FONT) {
@@ -406,7 +406,7 @@ void resource_manager::supply_resource(resource *r, int
rank,
     process_file(rank, fp, path, outfp);
     fclose(fp);
     if (r->type == RESOURCE_FONT)
-      free(path);
+      free(const_cast<char *>(path));
     if (outfp) {
       if (r->type == RESOURCE_FILE && is_document)
        fputs("%%EndDocument\n", outfp);
@@ -1098,7 +1098,7 @@ void resource_manager::process_file(int rank, FILE *fp,
 
 void resource_manager::read_download_file()
 {
-  char *path = 0 /* nullptr */;
+  const char *path = 0 /* nullptr */;
   FILE *fp = font::open_file("download", &path);
   if (0 /* nullptr */ == fp)
     fatal("cannot open 'download' file: %1", strerror(errno));
@@ -1115,7 +1115,7 @@ void resource_manager::read_download_file()
                               " font '%1'", p);
     lookup_font(p)->filename = strsave(q);
   }
-  free(path);
+  free(const_cast<char *>(path));
   fclose(fp);
 }
 
diff --git a/src/include/font.h b/src/include/font.h
index 85bae6719..39dd33c4b 100644
--- a/src/include/font.h
+++ b/src/include/font.h
@@ -218,7 +218,7 @@ public:
   static void command_line_font_dir(const char *);     // Prepend given
                        // path (arg1) to the list of directories in which
                        // to look up fonts.
-  static FILE *open_file(const char *, char **); // Open a font
+  static FILE *open_file(const char *, const char **); // Open a font
                        // description file with the given name (arg1),
                        // searching along the current font path, and
                        // rejecting `arg1` if it contains a slash (see
@@ -228,10 +228,10 @@ public:
                        // opened file's stream pointer.  If not found,
                        // arg2 is unchanged, and a null pointer is
                        // returned.
-  static FILE *open_resource_file(const char *, char **); // Open an
-                       // externally supplied (non-groff) file required
-                       // by the output driver, possibly to embed
-                       // content in the generated file.  Like
+  static FILE *open_resource_file(const char *, const char **); // Open
+                       // an externally supplied (non-groff) file
+                       // required by the output driver, possibly to
+                       // embed content in the generated file.  Like
                        // `open_file()` except that it accepts slashes
                        // in `arg1`.  Examples include Type 1 fonts
                        // embedded in PostScript output.
diff --git a/src/include/searchpath.h b/src/include/searchpath.h
index 65b94e8a0..af7c28298 100644
--- a/src/include/searchpath.h
+++ b/src/include/searchpath.h
@@ -25,8 +25,9 @@ public:
              int add_home, int add_current);
   ~search_path();
   void command_line_dir(const char *);
-  FILE *open_file(const char *, char **);
-  FILE *open_file_cautiously(const char *, char ** = 0 /* nullptr */,
+  FILE *open_file(const char *, const char **);
+  FILE *open_file_cautiously(const char *,
+                            const char ** = 0 /* nullptr */,
                             const char * = 0 /* nullptr */);
 };
 
diff --git a/src/include/stringclass.h b/src/include/stringclass.h
index 131c13718..f3736ddba 100644
--- a/src/include/stringclass.h
+++ b/src/include/stringclass.h
@@ -76,7 +76,7 @@ public:
   int search(const char) const;
   bool contains(const char) const;
   ssize_t find(const char *) const;
-  char *extract() const;
+  const char *extract() const;
   size_t json_length() const;
   const char *json_extract() const;
   void json_dump() const;
diff --git a/src/libs/libgroff/font.cpp b/src/libs/libgroff/font.cpp
index 362abf527..b6c1886e7 100644
--- a/src/libs/libgroff/font.cpp
+++ b/src/libs/libgroff/font.cpp
@@ -79,13 +79,13 @@ struct font_widths_cache {
 
 struct text_file {
   FILE *fp;
-  char *path;
+  const char *path;
   int lineno;
   int linebufsize;
   bool recognize_comments;
   bool silent;
   char *buf;
-  text_file(FILE *fp, char *p);
+  text_file(FILE *fp, const char *p);
   ~text_file();
   bool next_line();
   void error(const char *format,
@@ -98,8 +98,8 @@ struct text_file {
             const errarg &arg3 = empty_errarg);
 };
 
-text_file::text_file(FILE *p, char *s) : fp(p), path(s), lineno(0),
-  linebufsize(128), recognize_comments(true), silent(false),
+text_file::text_file(FILE *p, const char *s) : fp(p), path(s),
+  lineno(0), linebufsize(128), recognize_comments(true), silent(false),
   buf(0 /* nullptr */)
 {
 }
@@ -107,7 +107,7 @@ text_file::text_file(FILE *p, char *s) : fp(p), path(s),
lineno(0),
 text_file::~text_file()
 {
   delete[] buf;
-  free(path);
+  free(const_cast<char *>(path));
   if (fp)
     fclose(fp);
 }
@@ -898,7 +898,7 @@ again:
 
 bool font::load(bool want_diagnostic, bool validate_only)
 {
-  char *path;
+  const char *path;
   FILE *fp = open_file(filename, &path);
   if (0 /* nullptr */ == fp) {
     if (want_diagnostic)
@@ -1284,7 +1284,7 @@ static struct numeric_directive {
 const char *font::load_desc()
 {
   int nfonts = 0;
-  char *path;
+  const char *path;
   FILE *fp = open_file("DESC", &path);
   if (0 /* nullptr */ == fp)
     return 0 /* nullptr */;
diff --git a/src/libs/libgroff/fontfile.cpp b/src/libs/libgroff/fontfile.cpp
index 148fd3be3..13366eae6 100644
--- a/src/libs/libgroff/fontfile.cpp
+++ b/src/libs/libgroff/fontfile.cpp
@@ -64,7 +64,7 @@ void font::command_line_font_dir(const char *dir)
   font_path.command_line_dir(dir);
 }
 
-FILE *font::open_file(const char *nm, char **pathp)
+FILE *font::open_file(const char *nm, const char **pathp)
 {
   assert(nm != 0 /* nullptr */);
   assert(device != 0 /* nullptr */);
@@ -85,7 +85,7 @@ FILE *font::open_file(const char *nm, char **pathp)
   return fp;
 }
 
-FILE *font::open_resource_file(const char *nm, char **pathp)
+FILE *font::open_resource_file(const char *nm, const char **pathp)
 {
   assert(nm != 0 /* nullptr */);
   assert(device != 0 /* nullptr */);
diff --git a/src/libs/libgroff/searchpath.cpp
b/src/libs/libgroff/searchpath.cpp
index 3ad25a704..4ed59b0d5 100644
--- a/src/libs/libgroff/searchpath.cpp
+++ b/src/libs/libgroff/searchpath.cpp
@@ -113,7 +113,7 @@ void search_path::command_line_dir(const char *s)
   delete[] old;
 }
 
-FILE *search_path::open_file(const char *name, char **pathp)
+FILE *search_path::open_file(const char *name, const char **pathp)
 {
   assert(name != 0 /* nullptr */);
   if (IS_ABSOLUTE(name) || *dirs == '\0') {
@@ -174,7 +174,8 @@ FILE *search_path::open_file(const char *name, char
**pathp)
   return 0 /* nullptr */;
 }
 
-FILE *search_path::open_file_cautiously(const char *name, char **pathp,
+FILE *search_path::open_file_cautiously(const char *name,
+                                       const char **pathp,
                                        const char *mode)
 {
   if (0 /* nullptr */ == mode)
diff --git a/src/libs/libgroff/string.cpp b/src/libs/libgroff/string.cpp
index eb01c3078..0fb810dbd 100644
--- a/src/libs/libgroff/string.cpp
+++ b/src/libs/libgroff/string.cpp
@@ -372,7 +372,7 @@ ssize_t string::find(const char *c) const
 // Return pointer to null-terminated C string; any nulls internal to the
 // string are omitted.  The caller is responsible for `free()`ing the
 // returned storage.
-char *string::extract() const
+const char *string::extract() const
 {
   char *p = ptr;
   size_t n = len;
@@ -381,15 +381,18 @@ char *string::extract() const
   for (i = 0; i < n; i++)
     if (p[i] == '\0')
       nnuls++;
-  char *q = static_cast<char *>(calloc(n + 1 - nnuls, sizeof(char)));
+  size_t extracted_length = n + 1 /* '\0' */ - nnuls;
+  //char *q = static_cast<char *>(calloc(n + 1 - nnuls, sizeof(char)));
+  string *q = new string;
+  //(void) memset(q, 0, extracted_length);
   if (q != 0 /* nullptr */) {
-    char *r = q;
+    q->set_length(extracted_length);
     for (i = 0; i < n; i++)
       if (p[i] != '\0')
-       *r++ = p[i];
-    *r = '\0';
+       *q++ = p[i];
+    *q = '\0';
   }
-  return q;
+  return q->contents();
 }
 
 // Compute length of JSON representation of object.
diff --git a/src/preproc/eqn/main.cpp b/src/preproc/eqn/main.cpp
index 2574f7d37..a9ac291a5 100644
--- a/src/preproc/eqn/main.cpp
+++ b/src/preproc/eqn/main.cpp
@@ -467,13 +467,13 @@ int main(int argc, char **argv)
           " 'groff -Thtml -e')\n", device);
   }
   if (want_startup_file) {
-    char *path;
+    const char *path;
     FILE *fp = config_macro_path.open_file(STARTUP_FILE, &path);
     if (fp != 0 /* nullptr */) {
       do_file(fp, path);
       if (fclose(fp) < 0)
        fatal("cannot close '%1': %2", STARTUP_FILE, strerror(errno));
-      free(path);
+      free(const_cast<char *>(path));
     }
     else
       error("cannot open startup file '%1': %2", STARTUP_FILE,
diff --git a/src/preproc/grn/main.cpp b/src/preproc/grn/main.cpp
index dc2835f0e..773c611dd 100644
--- a/src/preproc/grn/main.cpp
+++ b/src/preproc/grn/main.cpp
@@ -577,7 +577,7 @@ conv(FILE *fp,
          error("no picture file name at line %1", baseline);
        return;
       }
-      char *path;
+      const char *path;
       gfp = macro_path.open_file(gremlinfile, &path);
       if (0 /* nullptr */ == gfp) {
        error("cannot open picture file '%1': %2", gremlinfile,
@@ -586,7 +586,7 @@ conv(FILE *fp,
       }
       PICTURE = DBRead(gfp);   /* read picture file */
       fclose(gfp);
-      free(path);
+      free(const_cast<char *>(path));
       if (DBNullelt(PICTURE))
        return;                 /* If a request is made to make the  */
                                /* picture fit into a specific area, */
diff --git a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp
index 7b6993db2..e9c87c52d 100644
--- a/src/preproc/html/pre-html.cpp
+++ b/src/preproc/html/pre-html.cpp
@@ -330,7 +330,7 @@ static bool get_line(FILE *f, const char *file_name, int
lineno)
 
 static unsigned int get_resolution(void)
 {
-  char *pathp;
+  const char *pathp;
   FILE *f;
   unsigned int res = 0;
   f = font_path.open_file(devps_desc, &pathp);
@@ -347,7 +347,7 @@ static unsigned int get_resolution(void)
        break;
     }
   }
-  free(pathp);
+  free(const_cast<char *>(pathp));
   fclose(f);
   return res;
 }
@@ -360,7 +360,7 @@ static unsigned int get_resolution(void)
 
 static char *get_image_generator(void)
 {
-  char *pathp;
+  const char *pathp;
   FILE *f;
   char *generator = 0 /* nullptr */;
   const char keyword[] = "image_generator";
@@ -393,7 +393,7 @@ static char *get_image_generator(void)
        break;
     }
   }
-  free(pathp);
+  free(const_cast<char *>(pathp));
   fclose(f);
   return generator;
 }
diff --git a/src/preproc/preconv/preconv.cpp
b/src/preproc/preconv/preconv.cpp
index cd13b5070..fdd74de9d 100644
--- a/src/preproc/preconv/preconv.cpp
+++ b/src/preproc/preconv/preconv.cpp
@@ -885,14 +885,18 @@ get_tag_lines(FILE *fp, string &data)
        data += char(c);
     }
   }
-  return data.extract();
+  // We need a mutable string.
+  const char *tag_lines_const = data.extract();
+  char *tag_lines = strdup(tag_lines_const); // XXX: leaky
+  free(const_cast<char *>(tag_lines_const));
+  return tag_lines;
 }
 
 // ---------------------------------------------------------
 // Indicate whether C string starts with a comment.
 // ---------------------------------------------------------
 static bool
-is_comment_line(char *s)
+is_comment_line(const char *s)
 {
   if (!s || !*s)
     return false;
@@ -1128,17 +1132,17 @@ do_file(const char *filename)
     fp = fopen(filename, FOPEN_RB);
     reported_filename = "'" + string(filename) + "'";
   }
-  char *c_reported_filename = reported_filename.extract();
+  const char *c_reported_filename = reported_filename.extract();
   if (!fp) {
     error("cannot open %1: %2", c_reported_filename, strerror(errno));
-    free(c_reported_filename);
+    free(const_cast<char *>(c_reported_filename));
     return false;
   }
   if (is_debugging) {
     fprintf(stderr, "processing %s\n", c_reported_filename);
     fflush(stderr);
   }
-  free(c_reported_filename);
+  free(const_cast<char *>(c_reported_filename));
   if (fseek(fp, 0L, SEEK_SET) == 0)
     is_seekable = true;
   else {
diff --git a/src/preproc/soelim/soelim.cpp b/src/preproc/soelim/soelim.cpp
index 1064edaef..68a61bb3f 100644
--- a/src/preproc/soelim/soelim.cpp
+++ b/src/preproc/soelim/soelim.cpp
@@ -194,7 +194,7 @@ static void do_so(const char *line)
 
 static bool do_file(const char *filename)
 {
-  char *file_name_in_path = 0 /* nullptr */;
+  const char *file_name_in_path = 0 /* nullptr */;
   FILE *fp = include_search_path.open_file_cautiously(filename,
       &file_name_in_path);
   int err = errno;
@@ -202,7 +202,7 @@ static bool do_file(const char *filename)
   if (strcmp(filename, "-") && file_name_in_path != 0 /* nullptr */)
     whole_filename = file_name_in_path;
   whole_filename += '\0';
-  free(file_name_in_path);
+  free(const_cast<char *>(file_name_in_path));
   if (0 /* nullptr */ == fp) {
     error("cannot open '%1': %2", whole_filename.contents(),
          strerror(err));
diff --git a/src/preproc/tbl/table.cpp b/src/preproc/tbl/table.cpp
index bd0abcda6..6b085bf77 100644
--- a/src/preproc/tbl/table.cpp
+++ b/src/preproc/tbl/table.cpp
@@ -1543,7 +1543,9 @@ void table::add_entry(int r, int c, const string &str,
   allocate(r);
   table_entry *e = 0 /* nullptr */;
   ssize_t len = str.length();
-  char *s = str.extract();
+  const char *s_const = str.extract();
+  // We need a mutable string.
+  char *s = strdup(s_const); // XXX: leaky
   // Diagnose escape sequences that can wreak havoc in generated output.
   if (len > 1) {
     // A comment on a control line or in a text block is okay.
@@ -1648,7 +1650,9 @@ void table::add_entry(int r, int c, const string &str,
       e = new empty_entry(this, f);
     }
     else {
-      char *glyph = str.substring(2, len - 2).extract();
+      const char *glyph_const = str.substring(2, len - 2).extract();
+      // We need a mutable string.
+      char *glyph = strdup(glyph_const); // XXX: leaky
       e = new repeated_char_entry(this, f, glyph);
     }
   }
diff --git a/src/roff/troff/env.cpp b/src/roff/troff/env.cpp
index 8f4542d89..a71ed55ea 100644
--- a/src/roff/troff/env.cpp
+++ b/src/roff/troff/env.cpp
@@ -4454,7 +4454,7 @@ void hyphen_trie::interpret_patterns_file(const char
*name,
     buf[i] = 0;
   int num[WORD_MAX + 1];
   errno = 0;
-  char *path = 0;
+  const char *path = 0;
   FILE *fp = mac_path->open_file(name, &path);
   if (0 /* nullptr */ == fp) {
     error("cannot open hyphenation pattern file '%1': %2", name,
@@ -4582,7 +4582,7 @@ void hyphen_trie::interpret_patterns_file(const char
*name,
     }
   }
   fclose(fp);
-  free(path);
+  free(const_cast<char *>(path));
   return;
 }
 
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index c9e6be2ac..8b6ae00e3 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -9831,7 +9831,7 @@ static void parse_output_page_list(const char *p)
   }
 }
 
-static FILE *open_macro_package(const char *mac, char **path)
+static FILE *open_macro_package(const char *mac, const char **path)
 {
   // Try `mac`.tmac first, then tmac.`mac`.  Expect ENOENT errors.
   // ISO C++ does not permit VLAs on the stack.
@@ -9863,13 +9863,13 @@ static FILE *open_macro_package(const char *mac, char
**path)
 
 static void process_macro_package_argument(const char *mac)
 {
-  char *path;
+  const char *path;
   FILE *fp = open_macro_package(mac, &path);
   if (0 /* nullptr */ == fp)
     fatal("cannot open macro file named in '-m' command-line argument"
          " '%1': %2", mac, strerror(errno));
   const char *s = symbol(path).contents();
-  free(path);
+  free(const_cast<char *>(path));
   input_stack::push(new file_iterator(fp, s));
   tok.next();
   process_input_stack();
@@ -9877,13 +9877,13 @@ static void process_macro_package_argument(const char
*mac)
 
 static void process_startup_file(const char *filename)
 {
-  char *path;
+  const char *path;
   search_path *orig_mac_path = mac_path;
   mac_path = &config_macro_path;
   FILE *fp = mac_path->open_file(filename, &path);
   if (fp != 0 /* nullptr */) {
     input_stack::push(new file_iterator(fp, symbol(path).contents()));
-    free(path);
+    free(const_cast<char *>(path));
     tok.next();
     process_input_stack();
   }
@@ -9896,11 +9896,11 @@ static void process_startup_file(const char
*filename)
 static void do_macro_source(bool quietly)
 {
   char *macro_filename = read_rest_of_line_as_argument();
-  char *path;
+  const char *path;
   FILE *fp = mac_path->open_file(macro_filename, &path);
   if (fp != 0 /* nullptr */) {
     input_stack::push(new file_iterator(fp, macro_filename));
-    free(path);
+    free(const_cast<char *>(path));
   }
   else
     // Suppress diagnostic only if we're operating quietly and it's an










    _______________________________________________________

Reply to this item at:

  <https://savannah.gnu.org/bugs/?68585>

_______________________________________________
Message sent via Savannah
https://savannah.gnu.org/

Attachment: signature.asc
Description: PGP signature

Reply via email to