Update of bug #68786 (group groff):
Status: Confirmed => In Progress
Planned Release: None => 1.25.0
Summary: [troff] empty string interpolation given as argument
to several requests cause assertion failures since 1.24.0 => [PATCH] [troff]
empty string interpolation given as argument to several requests cause
assertion failures since 1.24.0
_______________________________________________________
Follow-up Comment #1:
commit ff2b3000491b9bcc58022023091b45634168fd87
Author: G. Branden Robinson <[email protected]>
Date: Sat Oct 17 08:06:55 2026 -0500
XXX [troff]: Fix Savannah #68786.
Before:
$ for req in pso close pi sy; do printf '.%s \\*[undefined]\n' $req \
| groff -U; done
troff: ../src/roff/troff/input.cpp:7681: void pipe_source_request():
Assertion `pcmd != 0' failed.
groff: error: troff: Aborted (core dumped)
troff: ../src/roff/troff/input.cpp:8586: void close_request(): Assertion
`stream != 0' failed.
groff: error: troff: Aborted (core dumped)
troff: ../src/roff/troff/input.cpp:9619: void pipe_output(): Assertion `pc
!= 0' failed.
groff: error: troff: Aborted (core dumped)
troff: ../src/roff/troff/input.cpp:9661: void system_request(): Assertion
`command != 0' failed.
groff: error: troff: Aborted (core dumped)
After:
$ for req in pso close pi sy; do printf '.%s \\*[undefined]\n' $req \
| ./build/test-groff -U; done
troff:<standard input>:1: error: cannot apply piped command source request
to empty argument
troff:<standard input>:1: error: cannot apply close request to empty
argument
troff:<standard input>:1: error: cannot apply pipe request to empty
command
troff:<standard input>:1: error: cannot apply system request to empty
command
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index 8ac1bbce9..d0f595cf5 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -2203,6 +2203,22 @@ void token::diagnose_non_character()
// advance the input stream cursor (such as calling `read_identifier()`)
// beforehand. If the current token is not a space, an argument does
// not "lie ahead", and the request handler's logic may fail.
+//
+// Note 2: The caller _still_ must check for a null pointer after
+// calling `read_rest_of_line_as_argument()`, because the rest of the
+// line may consist of an empty string interpolation. Consider:
+// .ds fn \" empty
+// .so \*[fn]
+// Why is this not true of other lexical consumption functions, like
+// `read_identifier()` or `read_long_identifier()`? Because they bound
+// their reads by the input line's spaces, not (just) its terminating
+// newline. Consider:
+// .ds colorname \" empty
+// .defcolor \*[colorname] gray 0.5f
+// After string interpolation, this reads like:
+// .defcolor gray 0.5f
+// ...so the color name is "gray" and the request handler rejects "0.5f"
+// as an invalid color space.
bool has_arg(bool peeking)
{
if (!tok.is_space())
@@ -7687,11 +7703,12 @@ static void pipe_source_request() // .pso
return;
}
char *pcmd = read_rest_of_line_as_argument();
- // `has_arg()` should have ensured that this pointer is non-null.
- assert(pcmd != 0 /* nullptr */);
- if (0 /* nullptr */ == pcmd)
+ if (0 /* nullptr */ == pcmd) {
error("cannot apply piped command source request to empty"
" argument");
+ tok.next();
+ return;
+ }
errno = 0;
FILE *fp = popen(pcmd, POPEN_RT);
if (fp != 0 /* nullptr */)
@@ -8592,9 +8609,9 @@ static void close_request() // .close
return;
}
symbol stream = read_identifier();
- // Testing has_arg() should have ensured this.
- assert(stream != 0 /* nullptr */);
- if (!stream.is_null())
+ if (stream.is_null())
+ error("cannot apply close request to empty argument");
+ else
close_stream(stream);
skip_line();
}
@@ -9625,8 +9642,6 @@ static void pipe_output() // .pi
return;
}
char *pc = read_rest_of_line_as_argument();
- // `has_arg()` should have ensured that this pointer is non-null.
- assert(pc != 0 /* nullptr */);
if (0 /* nullptr */ == pc)
error("cannot apply pipe request to empty command");
// Are we adding to an existing pipeline?
@@ -9667,8 +9682,6 @@ static void system_request() // .sy
return;
}
char *command = read_rest_of_line_as_argument();
- // `has_arg()` should have ensured that this pointer is non-null.
- assert(command != 0 /* nullptr */);
if (0 /* nullptr */ == command)
error("cannot apply system request to empty command");
else
_______________________________________________________
Reply to this item at:
<https://savannah.gnu.org/bugs/?68786>
_______________________________________________
Message sent via Savannah
https://savannah.gnu.org/
signature.asc
Description: PGP signature
