Commit adc444e0 for tesseract
commit adc444e0edd1fcce11a3ff30b82be250599d4639
Author: Stefan Weil <sw@weilnetz.de>
Date: Fri Nov 13 17:31:00 2026 +0100
training: fix crashes in AddSpacingInfo for a missing or bad xheight
MasterTrainer::AddSpacingInfo() divides by xheights_[fontinfo_id], but
xheights_ only gets its size from LoadXHeights(), which is only called
if the option -X was given, and LoadXHeights() accepted any integer.
Without -X the code read from an empty vector (SIGSEGV), and with an
x-height of 0 it divided by zero (SIGFPE).
Ignore the spacing file with a message if the font has no valid
x-height, like it is done for a file which matches no font. Also skip
x-heights which are not positive in LoadXHeights(), so such a font
gets the mean of the valid entries.
Fix proposed by the Anthropic OSS Scanner (finding ANT-2026-TUPX5CXU).
Assisted-by: OpenCode / Claude Fable 5.2 (Anthropic)
Signed-off-by: Stefan Weil <sw@weilnetz.de>
diff --git a/src/training/common/mastertrainer.cpp b/src/training/common/mastertrainer.cpp
index a411a697..f8dddd91 100644
--- a/src/training/common/mastertrainer.cpp
+++ b/src/training/common/mastertrainer.cpp
@@ -440,6 +440,11 @@ bool MasterTrainer::LoadXHeights(const char *filename) {
// fontinfo not in table.
continue;
}
+ if (xht <= 0) {
+ tprintf("Ignoring invalid xheight %d for font %s in %s\n", xht, buffer,
+ filename);
+ continue;
+ }
xheights_[fontinfo_id] = xht;
total_xheight += xht;
++xheight_count;
@@ -472,6 +477,15 @@ bool MasterTrainer::AddSpacingInfo(const char *filename) {
fclose(fontinfo_file);
return false;
}
+ // The spacing is scaled by the xheight of the font, which is only known if
+ // an xheights file was loaded (see LoadXHeights) and has an entry for it.
+ if (static_cast<size_t>(fontinfo_id) >= xheights_.size() ||
+ xheights_[fontinfo_id] <= 0) {
+ tprintf("No xheight for font %d, ignoring spacing file %s\n", fontinfo_id,
+ filename);
+ fclose(fontinfo_file);
+ return false;
+ }
tprintf("Reading spacing from %s for font %d...\n", filename, fontinfo_id);
// TODO(rays) scale should probably be a double, but keep as an int for now
// to duplicate current behavior.