Skip to content

gh-136063: Fix quadratic complexity in email.header.decode_header() - #162002

Open
mountain-beaver wants to merge 1 commit into
python:mainfrom
mountain-beaver:gh-136063-decode-header-linear
Open

mountain-beaver wants to merge 1 commit into
python:mainfrom
mountain-beaver:gh-136063-decode-header-linear

Conversation

@mountain-beaver

Copy link
Copy Markdown

email.header.decode_header() is listed in gh-136063 among the functions with quadratic worst-case complexity. It had three separate O(n)-per-step operations:

  • parts.pop(0) in a loop over the result of ecre.split();
  • del words[d] in a loop to drop the whitespace between adjacent encoded words;
  • last_word += word on bytes to collapse runs of words with the same charset.

The split result is now walked by index, the word list is rebuilt in one pass, and each run is joined once. The output is unchanged: I compared the old and new implementations on 200,000 random header values (encoded words, plain text, whitespace, line breaks, malformed words), checking both return values and raised exceptions.

Timings on a release build, one header line of n copies of =?us-ascii?q?a?= :

n size before after
50,000 850 KB 2.29 s 0.095 s
100,000 1.7 MB 9.6 s 0.19 s
200,000 3.4 MB — 0.37 s

The new test follows test_get_param_linear_complexity: it uses 100,000 encoded words, which takes about a minute with the old code on a debug build.

…er()

decode_header() popped items from the front of the ecre.split() result,
deleted whitespace words from the middle of the word list one by one and
built runs of encoded words with repeated bytes concatenation.  All three
are O(n) per step, making the function quadratic in the number of
encoded words.  Walk the split result by index, rebuild the word list in
one pass and join each run once.
@mountain-beaver
mountain-beaver requested a review from a team as a code owner November 14, 2026 13:43
@python-cla-bot

python-cla-bot Bot commented Nov 14, 2026 •

Copy link
Copy Markdown

All commit authors signed the Contributor License Agreement.

CLA signed

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant