URL:
  <https://savannah.gnu.org/bugs/?68555>

                 Summary: [PATCH] [troff] ASAN runtime error: 1-byte heap
overread in `print_hyphenation_exceptions_request()`
                   Group: GNU roff
               Submitter: gbranden
               Submitted: Fri 24 Jul 2026 07:16:37 AM UTC
                Category: Core
                Severity: 4 - Important
              Item Group: Crash/Unresponsive
                  Status: In Progress
                 Privacy: Public
             Assigned to: gbranden
             Open/Closed: Open
         Discussion Lock: Unlocked
         Planned Release: None


    _______________________________________________________

Follow-up Comments:


-------------------------------------------------------
Date: Fri 24 Jul 2026 07:16:37 AM UTC By: G. Branden Robinson <gbranden>
Illustration with instrumented function.

My code for dumping hyphenation exception words didn't properly handle the
case where the exception word has no hyphenation points at all.  (It issued a
correct _report_, but read one byte too far while doing so.)


$ ../src/roff/groff/tests/phw-request-works.sh 
baz-qux
tab-le
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
word=imagemagick 
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=0, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=1, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=2, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=3, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=4, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=5, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=6, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=7, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=8, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=9, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=10, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=11, hypoint is not null
image-magick    *
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
word=xviiith 
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=0, hypoint is not null
troff:<standard input>:6: debug: GBR: print_hyphenation_exceptions_request:
i=1, hypoint is not null
=================================================================
==30964==ERROR: AddressSanitizer: heap-buffer-overflow on address
0x6020000d0971 at pc 0x55f01f0aaad2 bp 0x7fff495510b0 sp 0x7fff495510a8
READ of size 1 at 0x6020000d0971 thread T0
    #0 0x55f01f0aaad1 in print_hyphenation_exceptions_request
../src/roff/troff/env.cpp:4196
    #1 0x55f01f0ae135 in request::invoke(symbol, bool)
../src/roff/troff/input.cpp:3921
    #2 0x55f01f0bffff in interpolate_macro_or_invoke_request
../src/roff/troff/input.cpp:4755
    #3 0x55f01f0c9ca1 in process_input_stack()
../src/roff/troff/input.cpp:3649
    #4 0x55f01f0de526 in process_input_file ../src/roff/troff/input.cpp:9948
    #5 0x55f01f0ed58e in main ../src/roff/troff/input.cpp:10319
    #6 0x7f868028bd79 in __libc_start_main ../csu/libc-start.c:308
    #7 0x55f01f03e7e9 in _start
(/home/branden/src/GIT/groff/build/troff+0xbe7e9)

0x6020000d0971 is located 0 bytes to the right of 1-byte region
[0x6020000d0970,0x6020000d0971)
allocated by thread T0 here:
    #0 0x7f86808127a7 in operator new[](unsigned long)
../../../../src/libsanitizer/asan/asan_new_delete.cpp:102
    #1 0x55f01f07bac6 in hyphen_trie::insert_hyphenation(dictionary*, char
const*, int) ../src/roff/troff/env.cpp:4331
    #2 0x55f01f07bac6 in hyphen_trie::interpret_patterns_file(char const*,
bool, dictionary*) ../src/roff/troff/env.cpp:4574

SUMMARY: AddressSanitizer: heap-buffer-overflow ../src/roff/troff/env.cpp:4196
in print_hyphenation_exceptions_request
Shadow bytes around the buggy address:
  0x0c04800120d0: fa fa 01 fa fa fa 02 fa fa fa 01 fa fa fa 03 fa
  0x0c04800120e0: fa fa 02 fa fa fa 02 fa fa fa 01 fa fa fa 01 fa
  0x0c04800120f0: fa fa 02 fa fa fa 03 fa fa fa 02 fa fa fa 03 fa
  0x0c0480012100: fa fa 03 fa fa fa 02 fa fa fa 04 fa fa fa 02 fa
  0x0c0480012110: fa fa 02 fa fa fa 01 fa fa fa 01 fa fa fa 03 fa
=>0x0c0480012120: fa fa 01 fa fa fa 01 fa fa fa 01 fa fa fa[01]fa
  0x0c0480012130: fa fa 01 fa fa fa 01 fa fa fa 01 fa fa fa 02 fa
  0x0c0480012140: fa fa 02 fa fa fa 02 fa fa fa 03 fa fa fa fd fd
  0x0c0480012150: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480012160: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
  0x0c0480012170: fa fa fd fd fa fa fd fd fa fa fd fd fa fa fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==30964==ABORTING


I have a fix.


$ git diff src/roff/
diff --git a/src/roff/troff/env.cpp b/src/roff/troff/env.cpp
index 5b2cbaf7c..e8d3ed1c8 100644
--- a/src/roff/troff/env.cpp
+++ b/src/roff/troff/env.cpp
@@ -4189,6 +4189,7 @@ static void print_hyphenation_exceptions_request() //
.phw
     (void) memset(wordbuf, '\0', bufsz);
     size_t i = 0, j = 0, len = word.length();
     bool is_mode_dependent = false;
+    if (*hypoint != 0) {
     while (i < len) {
       if ((hypoint != 0 /* nullptr */) && (*hypoint == i)) {
        wordbuf[j++] = '-';
@@ -4203,6 +4204,7 @@ static void print_hyphenation_exceptions_request() //
.phw
       }
       wordbuf[j++] = word[i++];
     }
+    }
     errprint("%1", wordbuf);
     if (is_mode_dependent)
       errprint("\t*");


Indentation will need to be updated.  And as a bonus this change avoids
unnecessary work...not like the `phw` request is a hot path, though.







    _______________________________________________________

Reply to this item at:

  <https://savannah.gnu.org/bugs/?68555>

_______________________________________________
Message sent via Savannah
https://savannah.gnu.org/

Attachment: signature.asc
Description: PGP signature

Reply via email to