Skip to content

Race in pickle.dumps/loads per-interpreter cache leaks references #149000

Description

@CharlieKerfoot

Bug report

Bug description:

PyObject*dumps=state->pickle.dumps;
if (dumps!=NULL) {
returndumps;
}
dumps=PyImport_ImportModuleAttrString("pickle", "dumps");
if (dumps==NULL) returnNULL;
state->pickle.dumps=dumps;
returndumps;

This is a check-then-act race. Two threads in the same interpreter can both run this code:

  1. Thread A reads state->pickle.dumps → NULL
  2. Thread B reads state->pickle.dumps → NULL
  3. Thread A imports pickle.dumps, holds a strong reference R_A
  4. Thread B imports pickle.dumps, holds a strong reference R_B
  5. Thread A stores R_A into the slot
  6. Thread B stores R_B into the slot, overwriting R_A

Now the slot owns R_B, and R_A is leaked forever.

CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions