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/
signature.asc
Description: PGP signature
