Commit da03df91 for tesseract

commit da03df91674df117940188f0075c5a614bad53fa
Author: Stefan Weil <sw@weilnetz.de>
Date:   Sun Aug 9 15:07:08 2026 +0200

    Fix CID 1438664 (Wrapper object use after free)

    unichar_string() and unichar_lengths() rebuild their internal
    std::string members on every call, so the pointers obtained from
    c_str() at the start of one_ell_conflict became dangling as soon
    as unichar_string() was called again. Copy the strings into local
    variables to keep the pointers valid.

    Assisted-by: OpenCode / big-pickle (opencode)
    Signed-off-by: Stefan Weil <sw@weilnetz.de>

diff --git a/src/ccmain/reject.cpp b/src/ccmain/reject.cpp
index 6e370f19..f9c8c771 100644
--- a/src/ccmain/reject.cpp
+++ b/src/ccmain/reject.cpp
@@ -285,8 +285,6 @@ void Tesseract::reject_edge_blobs(WERD_RES *word) {
  * - A bundle of contextual heuristics!
  **********************************************************************/
 bool Tesseract::one_ell_conflict(WERD_RES *word_res, bool update_map) {
-  const char *word;
-  const char *lengths;
   int16_t word_len; // its length
   int16_t first_alphanum_index_;
   int16_t first_alphanum_offset_;
@@ -298,8 +296,12 @@ bool Tesseract::one_ell_conflict(WERD_RES *word_res, bool update_map) {
   bool dict_word_ok;
   int dict_word_type;

-  word = word_res->best_choice->unichar_string().c_str();
-  lengths = word_res->best_choice->unichar_lengths().c_str();
+  // unichar_string() and unichar_lengths() rebuild their internal strings,
+  // so copy them here to keep stable pointers for the rest of the function.
+  std::string word_str = word_res->best_choice->unichar_string();
+  std::string lengths_str = word_res->best_choice->unichar_lengths();
+  const char *word = word_str.c_str();
+  const char *lengths = lengths_str.c_str();
   word_len = strlen(lengths);
   /*
   If there are no occurrences of the conflict set characters then the word