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/

Attachment: signature.asc
Description: PGP signature

Reply via email to