gbranden pushed a commit to branch master
in repository groff.
commit 251115ed5a50345e6e0d4a8a78bd6c4c7d005808
Author: G. Branden Robinson <[email protected]>
AuthorDate: Mon May 19 21:09:05 2025 -0500
[troff]: Fix Savannah #67139.
Make diversion objects track whether they're "boxed" diversions; GNU
troff does not deal gracefully with opening a diversion as the regular
kind but trying to close it as a boxed one.
* src/roff/troff/div.h (class diversion): Add public member variable
`is_box`. Add Boolean argument to constructor with default value of
`false`.
(class macro_diversion): Add Boolean argument to constructor.
* src/roff/troff/div.cpp (diversion::diversion): Constructor now takes
`boxing` Boolean argument and sets `is_box` from it in the initializer
list.
(do_divert): Throw error diagnostics and ignore diversion closure
attempt if the request mismatches the box property of the current
diversion. It's a plain error in the `.box foo, .di` case and a fatal
one in `.di foo, .box` one because (only) the latter causes invalid
memory access.
Fixes Savannah #67139. Thanks to an anonymous submitter for the report.
Problem reproducible with groff 1.22.3 (2014), and appears to date back
at least to commit dc3c168c3b, 10 October 2004. Another guess would be
the introduction of box diversions in groff 1.17 (2001).
---
ChangeLog | 26 ++++++++++++++++++++++++++
src/roff/troff/div.cpp | 20 +++++++++++++-------
src/roff/troff/div.h | 7 ++++---
3 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 1a323c27d..15933fb35 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2025-05-19 G. Branden Robinson <[email protected]>
+
+ [troff]: Fix Savannah #67139. Make diversion objects track
+ whether they're "boxed" diversions; GNU troff does not deal
+ gracefully with opening a diversion as the regular kind but
+ trying to close it as a boxed one.
+
+ * src/roff/troff/div.h (class diversion): Add public member
+ variable `is_box`. Add Boolean argument to constructor with
+ default value of `false`.
+ (class macro_diversion): Add Boolean argument to constructor.
+ * src/roff/troff/div.cpp (diversion::diversion): Constructor now
+ takes `boxing` Boolean argument and sets `is_box` from it in the
+ initializer list.
+ (do_divert): Throw error diagnostics and ignore diversion
+ closure attempt if the request mismatches the box property of
+ the current diversion. It's a plain error in the `.box foo,
+ .di` case and a fatal one in `.di foo, .box` one because (only)
+ the latter causes invalid memory access.
+
+ Fixes Savannah #67139. Thanks to an anonymous submitter for the
+ report. Problem reproducible with groff 1.22.3 (2014), and
+ appears to date back at least to commit dc3c168c3b, 10 October
+ 2004. Another guess would be the introduction of box diversions
+ in groff 1.17 (2001).
+
2025-05-19 G. Branden Robinson <[email protected]>
[groff]: Regression-test Savannah #67139 (attempted closure of a
diff --git a/src/roff/troff/div.cpp b/src/roff/troff/div.cpp
index bd6461496..98f5959c8 100644
--- a/src/roff/troff/div.cpp
+++ b/src/roff/troff/div.cpp
@@ -1,4 +1,4 @@
-/* Copyright (C) 1989-2024 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2025 Free Software Foundation, Inc.
Written by James Clark ([email protected])
This file is part of groff.
@@ -53,9 +53,9 @@ static bool honor_vertical_position_traps = true;
static vunits truncated_space;
static vunits needed_space;
-diversion::diversion(symbol s)
+diversion::diversion(symbol s, bool boxing)
: prev(0 /* nullptr */), nm(s), vertical_position(V0),
- high_water_mark(V0), is_in_no_space_mode(false),
+ high_water_mark(V0), is_box(boxing), is_in_no_space_mode(false),
saved_seen_break(false), saved_seen_space(false),
saved_seen_eol(false), saved_suppress_next_eol(false),
marked_place(V0)
@@ -103,7 +103,13 @@ void do_divert(bool appending, bool boxing)
tok.skip();
symbol nm = get_name();
if (nm.is_null()) {
- if (curdiv->prev) {
+ // Why the asymmetric diagnostic severity? See Savannah #67139.
+ if (!(curdiv->is_box) && boxing)
+ fatal("cannot close ordinary diversion with box request");
+ if (curdiv->is_box && !boxing)
+ error("cannot close box diversion with ordinary diversion"
+ " request");
+ else if (curdiv->prev) {
curenv->seen_break = curdiv->saved_seen_break;
curenv->seen_space = curdiv->saved_seen_space;
curenv->seen_eol = curdiv->saved_seen_eol;
@@ -125,7 +131,7 @@ void do_divert(bool appending, bool boxing)
warning(WARN_DI, "diversion stack underflow");
}
else {
- macro_diversion *md = new macro_diversion(nm, appending);
+ macro_diversion *md = new macro_diversion(nm, appending, boxing);
md->prev = curdiv;
curdiv = md;
curdiv->saved_seen_break = curenv->seen_break;
@@ -180,8 +186,8 @@ void diversion::need(vunits n)
}
}
-macro_diversion::macro_diversion(symbol s, bool appending)
-: diversion(s), max_width(H0), diversion_trap(0 /* nullptr */),
+macro_diversion::macro_diversion(symbol s, bool appending, bool boxing)
+: diversion(s, boxing), max_width(H0), diversion_trap(0 /* nullptr */),
diversion_trap_pos(0)
{
#if 0
diff --git a/src/roff/troff/div.h b/src/roff/troff/div.h
index 4d734f74d..5db83b883 100644
--- a/src/roff/troff/div.h
+++ b/src/roff/troff/div.h
@@ -1,4 +1,4 @@
-/* Copyright (C) 1989-2024 Free Software Foundation, Inc.
+/* Copyright (C) 1989-2025 Free Software Foundation, Inc.
Written by James Clark ([email protected])
This file is part of groff.
@@ -35,6 +35,7 @@ protected:
vunits vertical_position;
vunits high_water_mark;
public:
+ bool is_box;
bool is_in_no_space_mode;
bool saved_seen_break; // XXX: nilpotent?
bool saved_seen_space; // XXX: nilpotent?
@@ -42,7 +43,7 @@ public:
bool saved_suppress_next_eol; // XXX: nilpotent?
state_set modified_tag;
vunits marked_place;
- diversion(symbol s = NULL_SYMBOL);
+ diversion(symbol /* s */ = NULL_SYMBOL, bool /* boxing */ = false);
virtual ~diversion();
virtual void output(node * /* nd */, bool /* retain_size */,
vunits /* vs */, vunits /* post_vs */,
@@ -73,7 +74,7 @@ class macro_diversion : public diversion {
symbol diversion_trap;
vunits diversion_trap_pos;
public:
- macro_diversion(symbol, bool /* appending */);
+ macro_diversion(symbol, bool /* appending */, bool /* boxing */);
~macro_diversion();
void output(node * /* nd */, bool /* retain_size */, vunits /* vs */,
vunits /* post_vs */, hunits /* width */);
_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit