[PR #13249/3c6cf44d backport][3.14] Fix segfault when decompression fails while draining pending data by patchback[bot] · Pull Request #13272 · aio-libs/aiohttp · GitHub
Skip to content

[PR #13249/3c6cf44d backport][3.14] Fix segfault when decompression fails while draining pending data - #13272

Merged
Dreamsorcerer merged 1 commit into
3.14from
patchback/backports/3.14/3c6cf44da3e5c984655c58784818ce5bf3f4d05c/pr-13249
Jul 27, 2026
Merged

Dreamsorcerer merged 1 commit into
3.14from
patchback/backports/3.14/3c6cf44da3e5c984655c58784818ce5bf3f4d05c/pr-13249

Conversation

@patchback

@patchback patchback Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

This is a backport of PR #13249 as merged into master (3c6cf44).

What do these changes do?

The llhttp callbacks in the C parser are declared except -1, which promises Cython that a -1 return always has an exception pending. The callbacks actually return -1 as a plain abort status after catching the error and stashing it for later delivery. That is fine when llhttp calls them, but feed_data also calls cb_on_body directly to drain pending decompressed data; when the decompressor raises during that drain, Cython takes the error path with no exception set and crashes in __Pyx_AddTraceback on Python 3.12 and newer. This happens in the wild with brotlicffi 1.2, see python-hyper/brotlicffi#225 and cython/cython#7857.

The callbacks are now declared except? -1 so Cython checks PyErr_Occurred() before taking the error path, and the drain call handles the failure explicitly; the error reaches the user through the payload as ContentEncodingError like other payload errors.

Are there changes in behavior for the user?

A decompression failure while draining pending data now raises ContentEncodingError instead of crashing the interpreter.

Is it a substantial burden for the maintainers to support this?

No, the exception declarations now match what the callbacks actually do.

Related issue number

Fixes #13203.

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes
  • If you provide code modification, please add yourself to CONTRIBUTORS.txt
    • The format is <Name> <Surname>.
    • Please keep alphabetical order, the file is sorted by names.
  • Add a new news fragment into the CHANGES/ folder
    • name it <issue_or_pr_num>.<type>.rst (e.g. 588.bugfix.rst)

    • if you don't have an issue number, change it to the pull request
      number after creating the PR

      • .bugfix: A bug fix for something the maintainers deemed an
        improper undesired behavior that got corrected to match
        pre-agreed expectations.
      • .feature: A new behavior, public APIs. That sort of stuff.
      • .deprecation: A declaration of future API removals and breaking
        changes in behavior.
      • .breaking: When something public is removed in a breaking way.
        Could be deprecated in an earlier release.
      • .doc: Notable updates to the documentation structure or build
        process.
      • .packaging: Notes for downstreams about unobvious side effects
        and tooling. Changes in the test invocation considerations and
        runtime assumptions.
      • .contrib: Stuff that affects the contributor experience. e.g.
        Running tests, building the docs, setting up the development
        environment.
      • .misc: Changes that are hard to assign to any of the above
        categories.
    • Make sure to use full sentences with correct case and punctuation,
      for example:

      Fixed issue with non-ascii contents in doctest text files
      -- by :user:`contributor-gh-handle`.

      Use the past tense or the present tense a non-imperative mood,
      referring to what's changed compared to the last released version
      of this project.

Test output

The new test reproduces the crash on the unfixed extension:

tests/test_http_parser.py Fatal Python error: Segmentation fault

With the fix, on Python 3.14.2 with the C extension built:

tests/test_http_parser.py::test_decompress_error_while_draining_pending_data[py-parser] PASSED
tests/test_http_parser.py::test_decompress_error_while_draining_pending_data[c-parser] PASSED
835 passed, 2 skipped, 6 deselected, 3 xfailed in 1.89s

Pure Python mode:

AIOHTTP_NO_EXTENSIONS=1: 1 passed

The regenerated call site in _http_parser.c now guards the error path:

if (unlikely(__pyx_t_5 == ((int)-1) && PyErr_Occurred())) __PYX_ERR(0, 637, __pyx_L1_error)

Drafted with Claude Code (Fable 5); reviewed by bdraco.

@codecov

codecov Bot commented Jul 27, 2026 •

Copy link
Copy Markdown

@codspeed

codspeed Bot commented Jul 27, 2026

Copy link
Copy Markdown

@Dreamsorcerer
Dreamsorcerer merged commit f793a69 into 3.14 Jul 27, 2026
46 checks passed
@Dreamsorcerer
Dreamsorcerer deleted the patchback/backports/3.14/3c6cf44da3e5c984655c58784818ce5bf3f4d05c/pr-13249 branch July 27, 2026 19:02
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.

2 participants