Skip to content

Memory leak in extractBLOCKS (_as_blocks): text object reference never released #5067

Description

@idlefella

Description of the bug

Description

The extractBLOCKS code path leaks a Python object for every text, image, and vector block on every call. Since extractBLOCKS (a.k.a. page.get_text("blocks")) is commonly called once per page in bulk-processing loops, the leak accumulates quickly across large/multi-page documents.

Location

src/extra.i, in the recursive helper _as_blocks (around line 3501).

Root cause

The block tuple is populated like this:

PyObject *litem = PyTuple_New(7);
...
PyTuple_SET_ITEM(litem, 4, Py_BuildValue("O", text));   // <-- leak
...

text is created as a new reference, via either:

  • JM_EscapeStrFromBuffer(res) (text blocks), or
  • PyUnicode_FromFormat(...) (image / vector blocks).

The "O" format code in Py_BuildValue increments the refcount of text and returns a separate new object. That separate object is the one stolen into the tuple by PyTuple_SET_ITEM. The original text reference is then discarded on the next iteration:

text = NULL;

…without ever being decref'd. Net effect: text is leaked once per block.

The other six PyTuple_SET_ITEM calls in the same block are correct — Py_BuildValue("f"/"i", ...) creates a fresh object the tuple legitimately owns.

Fix

Hand the original text reference to the tuple instead of creating an extra one. Since PyTuple_SET_ITEM steals a reference, set it directly:

PyTuple_SET_ITEM(litem, 4, text);

(Equivalently, Py_BuildValue("N", text), where "N" steals rather than increments.)

Environment

  • PyMuPDF: <fill in version, e.g. output of fitz.__doc__>
  • OS / Python: <fill in>

How to reproduce the bug

Reproduction

import pymupdf, os, psutil
doc = pymupdf.open("some_multipage.pdf")
p = psutil.Process(os.getpid())
for i in range(200):
    for page in doc:
        page.get_text("blocks")
    rss_mb = p.memory_info().rss / (1024 * 1024)  # Convert to MiB
    print(f"Iteration {i + 1}: {rss_mb:.2f} MiB")  # grows steadily

PyMuPDF version

1.27.2.2

Operating system

Linux

Python version

3.12

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions