python / python/cpython

concurrent.interpreters: crash (NULL dereference) when an unpickled AttributeError has a non-string arg

Open
#151,862 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

3.14 3.15 3.16 interpreter-core topic-subinterpreters type-bug
Dominant language
Python
Stars
77.2k
Forks
35.9k
PR merge metrics
PR metrics pending

Description

Python/crossinterp.c's check_missing___main___attr() passes the result of PyUnicode_AsUTF8() straight to strncmp() without a NULL check:

const char *err = PyUnicode_AsUTF8(msgobj);
// Check if it's a missing __main__ attr.
int cmp = strncmp(err, "module '__main__' has no attribute '", 36);

msgobj is args[0] of an AttributeError raised on the receive side of the cross-interpreter pickle fallback, reached when an object is moved between interpreters through a concurrent.interpreters queue or channel and its unpickling in the receiving interpreter fails.

PyUnicode_AsUTF8() returns NULL (and sets an exception) when args[0] is not a str — e.g. AttributeError(42), AttributeError(b'x'), AttributeError(None) — or is a str containing lone surrogates (AttributeError('\ud800')). When err == NULL, strncmp(NULL, ...) dereferences NULL and the interpreter crashes (SIGSEGV).

Reproduction

Put an object into a concurrent.interpreters queue whose unpickling on the receive side raises an AttributeError with a non-string (or surrogate) first argument, then get() it — the receiving interpreter segfaults instead of raising NotShareableError. A self-contained reproduction is added as a regression test (test_get_unpickle_fails_with_bad_attributeerror_arg in Lib/test/test_interpreters/test_queues.py), exercising args 42, b'x', None, and '\ud800'.

Scope

This is the check_missing___main___attr() NULL dereference reached through the queue/channel receive path. It does not by itself make every cross-interpreter unpickle failure safe — Interpreter.call() has a separate crash on its result-preserve path that I will report independently.

Fix

Add a NULL guard immediately after PyUnicode_AsUTF8, matching the correctly-checked sibling helper _copy_string_obj_raw(): on NULL, clear the exception (the function asserts !PyErr_Occurred() on entry), Py_DECREF(msgobj), and return 0 (not a missing-__main__ attribute).

Affected versions

concurrent.interpreters (PEP 734) is public in 3.14+; this reproduces on main and 3.14.

Linked PR

A PR follows.

Linked PRs
  • gh-151863

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

The issue points to Python/crossinterp.c and check_missing___main___attr(); compare its PyUnicode_AsUTF8() handling with the sibling _copy_string_obj_raw() helper. Run Lib/test/test_interpreters/test_queues.py, especially test_get_unpickle_fails_with_bad_attributeerror_arg, and confirm the listed malformed AttributeError arguments raise NotShareableError without a crash. A linked PR, gh-151863, indicates the work is already underway.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, python
Domain
compilers
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.