gbranden pushed a commit to branch master
in repository groff.
commit ec6e93c7368e823eaa8b44084730c9bbf4934a83
Author: G. Branden Robinson <[email protected]>
AuthorDate: Sun Apr 13 13:42:53 2025 -0500
[troff]: Refactor `grostream` for memory safety.
* src/roff/troff/input.cpp: Refactor `grostream` class for memory
safety.
(struct grosteam): Convert from this...
(class grostream): ...to this, inheriting from class `object` so that
it casts less dangerously thence and thither when stashing
`grostream`s into and retrieving them from `object_dictionary`
objects.
(class grostream): Also re-type `filename` and `mode` member variables
from (groff) `string` to `symbol`, since they won't have embedded null
characters (and take up half as much space; `sizeof (string)` is 16 on
GNU/Linux amd64 whereas that of `symbol` is 8). Making this change by
itself exposed memory corruption problems, resolved by resituating
`grostream` in the class hierarchy.
(grostream::grostream): Drop now unnecessary explicit null
termination. That property is implied by the `symbol` class.
(open_file): Make newly created object anonymous, and drop frightening
C-style typecast. Now a `grostream` casts safely and implicitly to
and from `object`.
Problem likely introduced by me in commit 6d32f2492, 24 September, but
it was latent (requiring the `symbol` change noted above), and without
JSON dumpers for `string` and `symbol` objects, visibility into memory
mischief was limited if it didn't cause a SEGV on a developer's
machine.
---
ChangeLog | 28 ++++++++++++++++++++++++++++
src/roff/troff/input.cpp | 20 +++++++++-----------
2 files changed, 37 insertions(+), 11 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index ef38d0767..e72b04435 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2025-04-13 G. Branden Robinson <[email protected]>
+
+ * src/roff/troff/input.cpp: Refactor `grostream` class for
+ memory safety.
+ (struct grosteam): Convert from this...
+ (class grostream): ...to this, inheriting from class `object` so
+ that it casts less dangerously thence and thither when stashing
+ `grostream`s into and retrieving them from `object_dictionary`
+ objects.
+ (class grostream): Also re-type `filename` and `mode` member
+ variables from (groff) `string` to `symbol`, since they won't
+ have embedded null characters (and take up half as much space;
+ `sizeof (string)` is 16 on GNU/Linux amd64 whereas that of
+ `symbol` is 8). Making this change by itself exposed memory
+ corruption problems, resolved by resituating `grostream` in the
+ class hierarchy.
+ (grostream::grostream): Drop now unnecessary explicit null
+ termination. That property is implied by the `symbol` class.
+ (open_file): Make newly created object anonymous, and drop
+ frightening C-style typecast. Now a `grostream` casts safely
+ and implicitly to and from `object`.
+
+ Problem likely introduced by me in commit 6d32f2492, 24
+ September, but it was latent (requiring the `symbol` change
+ noted above), and without JSON dumpers for `string` and `symbol`
+ objects, visibility into memory mischief was limited if it
+ didn't cause a SEGV on a developer's machine.
+
2025-04-13 G. Branden Robinson <[email protected]>
* src/libs/libgroff/symbol.cpp: Fix code style nits.
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index e30b3f751..eb015a5b3 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -7605,20 +7605,18 @@ void terminal_continue()
do_terminal(0, 1);
}
-struct grostream {
- string filename;
- string mode;
+class grostream : public object {
+public:
+ symbol filename;
+ symbol mode;
FILE *file;
- grostream(const string &fn, string m, FILE *fp);
+ grostream(const char *fn, symbol m, FILE *fp);
~grostream();
};
-grostream::grostream(const string &fn, string m, FILE *fp)
+grostream::grostream(const char *fn, symbol m, FILE *fp)
: filename(fn), mode(m), file(fp)
{
- // Don't leak garbage in print_streams().
- filename += '\0';
- mode += '\0';
}
// XXX: Maybe we should try to close the libc FILE stream here.
@@ -7663,7 +7661,7 @@ static void open_file(bool appending)
if (!stream.is_null()) {
char *filename = read_rest_of_line_as_argument();
if (filename != 0 /* nullptr */) {
- const string mode = appending ? "appending" : "writing";
+ const char *mode = appending ? "appending" : "writing";
errno = 0;
FILE *fp = fopen(filename, appending ? "a" : "w");
if (0 /* nullptr */ == fp) {
@@ -7686,8 +7684,8 @@ static void open_file(bool appending)
return;
}
}
- grostream *grost = new grostream(filename, mode, &*fp);
- stream_dictionary.define(stream, (object *)grost);
+ stream_dictionary.define(stream,
+ new grostream(filename, mode, &*fp));
}
}
// TODO: Add `filename` to file name set.
_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit