gbranden pushed a commit to branch master
in repository groff.

commit fb2432fe60225d6c34e43b630e67cbc1c24e61d5
Author: G. Branden Robinson <[email protected]>
AuthorDate: Sun May 17 14:32:33 2026 -0500

    [troff]: Remove heap-overreading optimization.
    
    * src/roff/troff/input.cpp (char_list::get): De-optimize read access at
      the end of a `char_list`, because the pointer arithmetic used can
      access heap storage beyond the end of the underlying `char_block` used
      to house the list.
    
    Fixes <https://savannah.gnu.org/bugs/?68340>.  Resolves ASAN runtime
    error when formatting the groff_mdoc(7) man page in troff mode.  Thanks
    to Bjarni Ingi Gislason for the report.
    
    Performance analysis
    ====================
    
    This change slows groff pipline operation by about 5% across the corpus
    of documents produced in its own build.  If someone would like to craft
    a new, more memory-safe optimization to recover the performance, please
    contact the groff at gnu dot org mailing list and share your proposal.
    
    (A better long-term fix might be to migrate `char_list` to an ISO C++98
    STL templated container type; these are often performance-tuned already
    by the compiler vendor.)
    
    $ cat measure.bash
    shopt -s extglob
    
    make -C build -j >/dev/null 2>&1
    
    for n in $(seq 20)
    do
            rm -f build/doc/!(groff).pdf build/doc/*.ps \
                    build/doc/!(groff).html \
                    build/contrib/hdtbl/examples/*.ps \
                    build/contrib/mom/examples/*.pdf \
                    contrib/sboxes/msboxes.pdf \
                    doc/groff-man-pages.utf8.txt
            t=$({ time -p make -C build >/dev/null 2>&1; } 2>/dev/stdout)
            echo "$t" | awk '/real/ { print $2; }'
    done
    
    Before
    ------
    
    $ bash ./measure.bash | tee | datamash range 1 mean 1 sstdev 1
    0.86    31.9025 0.24063239052218
    
    After
    -----
    
    $ bash ./measure.bash | tee | datamash range 1 mean 1 sstdev 1
    6.91    33.545  1.8817363202498
---
 ChangeLog                | 11 +++++++++++
 src/roff/troff/input.cpp |  4 ----
 2 files changed, 11 insertions(+), 4 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 1e14c8dd9..b1e70ef92 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2026-05-17  G. Branden Robinson <[email protected]>
+
+       * src/roff/troff/input.cpp (char_list::get): De-optimize read
+       access at the end of a `char_list`, because the pointer
+       arithmetic used can access heap storage beyond the end of the
+       underlying `char_block` used to house the list.
+
+       Fixes <https://savannah.gnu.org/bugs/?68340>.  Resolves ASAN
+       runtime error when formatting the groff_mdoc(7) man page in
+       troff mode.  Thanks to Bjarni Ingi Gislason for the report.
+
 2026-05-17  G. Branden Robinson <[email protected]>
 
        * src/roff/troff/input.cpp: Trivially refactor and fix code
diff --git a/src/roff/troff/input.cpp b/src/roff/troff/input.cpp
index ff6900247..3af87823c 100644
--- a/src/roff/troff/input.cpp
+++ b/src/roff/troff/input.cpp
@@ -4000,10 +4000,6 @@ void char_list::set(unsigned char c, int offset)
 unsigned char char_list::get(int offset)
 {
   assert(length > offset);
-  // optimization for access at the end
-  int boundary = length - (length % char_block::SIZE);
-  if (offset >= boundary)
-    return *(tail->s + offset - boundary);
   char_block *tem = head;
   int l = 0;
   for (;;) {

_______________________________________________
groff-commit mailing list
[email protected]
https://lists.gnu.org/mailman/listinfo/groff-commit

Reply via email to