Skip to content

fix(koptreflow): margin calculation, memory leaks, and div-by-zero - #68

Open
tachibana-shin wants to merge 5 commits into
koreader:masterfrom
tachibana-shin:fix/koptreflow-issues
Open

fix(koptreflow): margin calculation, memory leaks, and div-by-zero#68
tachibana-shin wants to merge 5 commits into
koreader:masterfrom
tachibana-shin:fix/koptreflow-issues

Conversation

@tachibana-shin

@tachibana-shin tachibana-shin commented Jul 22, 2026

Copy link
Copy Markdown
  • Fix copy-paste error: bottom margin used top margin index (box[1] → box[3])
  • Free previous BOXA/NUMA/wrectmaps before overwriting to prevent memory leaks
  • Guard division by zero when srcdpiw, srcdpih, or zoom is zero
  • Add input validation in pixmap_to_bmp() for null data and invalid dimensions

Problem 1: Copy-paste error in margin calculation

In lib/koptreflow.c:110, the bottom margin was calculated using the wrong index:

martop = (int) (k2settings->dst_dpi * k2settings->dstmargins.box[1] * 2 + .5);
marbot = (int) (k2settings->dst_dpi * k2settings->dstmargins.box[1] * 2 + .5);  // BUG

Both used box[1] (top margin). The box array is indexed as: box[0]=left, box[1]=top, box[2]=right, box[3]=bottom. The bottom margin should use box[3].

Fix

marbot = (int) (k2settings->dst_dpi * k2settings->dstmargins.box[3] * 2 + .5);

Problem 2: Memory leak on reflow

When k2pdfopt_reflow_bmp() is called multiple times (e.g. reflowing different pages), the previous rboxa, nboxa, rnai, nnai BOXA/NUMA objects are overwritten without being freed. Similarly, wrectmaps entries accumulate across calls.

Fix

Free previous allocations before creating new ones:

boxaDestroy(&kctx->rboxa);
boxaDestroy(&kctx->nboxa);
numaDestroy(&kctx->rnai);
numaDestroy(&kctx->nnai);
wrectmaps_clear(&kctx->rectmaps);

Problem 3: Division by zero

In the rectmaps loop, rectmap->srcdpiw, rectmap->srcdpih, and kctx->zoom are used as divisors without checking for zero:

nlbox = boxCreate(rectmap->coords[0].x*k2settings->src_dpi/rectmap->srcdpiw/kctx->zoom + ...,
                   rectmap->coords[0].y*k2settings->src_dpi/rectmap->srcdpih/kctx->zoom + ...,
                   ...);

Fix

Guard with zero checks:

BOX* nlbox = NULL;
if (rectmap->srcdpiw > 0. && rectmap->srcdpih > 0. && kctx->zoom > 0.) {
    nlbox = boxCreate(...);
}
if (nlbox != NULL)
    boxaAddBox(nboxa, nlbox, L_INSERT);

Problem 4: Unchecked input in pixmap_to_bmp()

pixmap_to_bmp() does not validate pix_data pointer or bitmap dimensions before accessing pixel memory.

Fix

if (!pix_data || bmp->width <= 0 || bmp->height <= 0)
    return;

This change is Reviewable

marbot used box[1] (top margin) instead of box[3] (bottom margin),
causing the bottom margin to be calculated with the wrong value.
When k2pdfopt_reflow_bmp() is called multiple times, the previous
rboxa/nboxa/rnai/nnai were overwritten without being freed, causing
memory leaks.
wrectmaps entries accumulated across calls to k2pdfopt_reflow_bmp()
because the rectmaps were not cleared before the loop that adds new
entries.
srcdpiw, srcdpih, and zoom are used as divisors without checking for
zero. When any of these is zero, the division causes undefined
behavior. Skip nlbox creation when divisors are not positive.
Validate pix_data pointer and bitmap dimensions before accessing
pixel memory. Returns early on null data or non-positive dimensions
instead of causing out-of-bounds reads.
@Frenzie

Frenzie commented Jul 22, 2026

Copy link
Copy Markdown
Member

@benoit-pierre You said you're also working on something. Should these PRs merged first or after?

@benoit-pierre

Copy link
Copy Markdown
Member

I would be great if could please hold off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants