Commit 9e719c15 for tesseract

commit 9e719c155f8b89372fc5443602acba6d9e67555e
Author: Stefan Weil <sw@weilnetz.de>
Date:   Fri Nov 13 17:31:00 2026 +0100

    ccmain: fix read out of bounds in PrerecAllWordsPar for an empty word

    PrerecAllWordsPar() (tessedit_parallelize) assumes that each ratings
    matrix has a cell (0, 0). In LSTM-only mode a word without blobs is
    not replaced by a fake word, so its ratings matrix has dimension 0,
    and get(0, 0) read behind the empty array.

    Skip such a word. It has no blobs which could be classified.

    Fix proposed by the Anthropic OSS Scanner (finding ANT-2026-XHAFVBQP).

    Assisted-by: OpenCode / Claude Fable 5.2 (Anthropic)
    Signed-off-by: Stefan Weil <sw@weilnetz.de>

diff --git a/src/ccmain/par_control.cpp b/src/ccmain/par_control.cpp
index 731bd19a..17203949 100644
--- a/src/ccmain/par_control.cpp
+++ b/src/ccmain/par_control.cpp
@@ -54,7 +54,10 @@ void Tesseract::PrerecAllWordsPar(const std::vector<WordData> &words) {
   // Prepare all the blobs.
   std::vector<BlobData> blobs;
   for (const auto &w : words) {
-    if (w.word->ratings != nullptr && w.word->ratings->get(0, 0) == nullptr) {
+    // In LSTM mode a word with no blobs is not faked, so its ratings matrix
+    // can be empty; there is nothing to pre-classify in that case.
+    if (w.word->ratings != nullptr && w.word->ratings->dimension() > 0 &&
+        w.word->ratings->get(0, 0) == nullptr) {
       for (size_t s = 0; s < w.lang_words.size(); ++s) {
         Tesseract *sub = s < sub_langs_.size() ? sub_langs_[s] : this;
         const WERD_RES &word = *w.lang_words[s];