Commit 28e7e676 for tesseract
commit 28e7e6768dcc9b292a2dc6baf0e871d05665c161
Author: Stefan Weil <sw@weilnetz.de>
Date: Fri Nov 13 17:30:08 2026 +0100
textord: avoid divisions by zero for three integer parameters
textord_noise_sizefraction, edges_children_per_grandchild and
textord_spline_medianwin are used as divisors without any check, so a
value of 0 from a config file ended the process with SIGFPE.
textord_spline_medianwin is also used as the size of a median window,
and a value below 1 caused a read out of bounds in segment_baseline().
- clean_noise_from_row() and clean_noise_from_words() use the blob
size as the threshold if textord_noise_sizefraction is not positive.
- OL_BUCKETS::count_children() counts no grandchildren if
edges_children_per_grandchild is not positive.
- segment_baseline() falls back to a straight baseline if
textord_spline_medianwin is not positive.
Nothing changes for positive values.
This is not a complete fix for all parameters: there are more
parameters which are used as divisors in floating point calculations
without a check.
Fix proposed by the Anthropic OSS Scanner (finding ANT-2026-I7UIR1ID).
Assisted-by: OpenCode / Claude Fable 5.2 (Anthropic)
Signed-off-by: Stefan Weil <sw@weilnetz.de>
diff --git a/src/textord/edgblob.cpp b/src/textord/edgblob.cpp
index e9a327e0..8d7b2fa4 100644
--- a/src/textord/edgblob.cpp
+++ b/src/textord/edgblob.cpp
@@ -231,8 +231,12 @@ int32_t OL_BUCKETS::count_children( // recursive count
if (child != outline && *child < *outline) {
child_count++;
if (child_count <= max_count) {
+ // Avoid an integer division by zero if the parameter is not
+ // positive.
int max_grand =
- (max_count - child_count) / edges_children_per_grandchild;
+ edges_children_per_grandchild > 0
+ ? (max_count - child_count) / edges_children_per_grandchild
+ : 0;
if (max_grand > 0) {
grandchild_count += count_children(child, max_grand) *
edges_children_per_grandchild;
diff --git a/src/textord/makerow.cpp b/src/textord/makerow.cpp
index 692c646e..d5d98022 100644
--- a/src/textord/makerow.cpp
+++ b/src/textord/makerow.cpp
@@ -2103,7 +2103,10 @@ bool segment_baseline( // split baseline
if (textord_oldbl_debug) {
tprintf("Segmenting baseline of %d blobs at (%d,%d)\n", blobcount, box.left(), box.bottom());
}
- if (blobcount <= textord_spline_medianwin || blobcount < textord_spline_minblobs) {
+ // A window size which is not positive cannot be used for the median below
+ // nor as a divisor in linear_spline_baseline.
+ if (textord_spline_medianwin < 1 || blobcount <= textord_spline_medianwin ||
+ blobcount < textord_spline_minblobs) {
blob_it.move_to_last();
box = blob_it.data()->bounding_box();
xstarts[1] = box.right();
diff --git a/src/textord/tordmain.cpp b/src/textord/tordmain.cpp
index e59528da..69222cca 100644
--- a/src/textord/tordmain.cpp
+++ b/src/textord/tordmain.cpp
@@ -515,7 +515,9 @@ bool Textord::clean_noise_from_row( // remove empties
blob_size = blob_box.width() > blob_box.height() ? blob_box.width() : blob_box.height();
if (blob_size >= textord_noise_sizelimit * row->x_height() &&
blob_size < row->x_height() * 2) {
- trans_threshold = blob_size / textord_noise_sizefraction;
+ // Avoid an integer division by zero if the parameter is not positive.
+ trans_threshold = textord_noise_sizefraction > 0 ? blob_size / textord_noise_sizefraction
+ : blob_size;
trans_count = blob->count_transitions(trans_threshold);
if (trans_count < textord_noise_translimit) {
norm_count++;
@@ -612,7 +614,9 @@ void Textord::clean_noise_from_words( // remove empties
blob_size = blob_box.width() > blob_box.height() ? blob_box.width() : blob_box.height();
if (blob_size >= textord_noise_sizelimit * row->x_height() &&
blob_size < row->x_height() * 2) {
- trans_threshold = blob_size / textord_noise_sizefraction;
+ // Avoid an integer division by zero if the parameter is not positive.
+ trans_threshold = textord_noise_sizefraction > 0 ? blob_size / textord_noise_sizefraction
+ : blob_size;
trans_count = blob->count_transitions(trans_threshold);
if (trans_count < textord_noise_translimit) {
norm_count++;