python / python/cpython

reference leak when a JIT trace is rewound

Open
#157,875 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

type-bug
Dominant language
Python
Stars
77.2k
Forks
36k
Avg merge
1d 9h
Merged PRs (30d)
558

Description

Bug report

Bug description:
import gc
import sys
import weakref

def run():
    class C:
        def __iter__(self):
            return self
        def __next__(self):
            raise StopIteration

    obj = C()
    for _ in range(10_000):
        for _ in obj:
            pass
    return weakref.ref(C)


ref = run()
gc.collect()
print("jit enabled:", sys._jit.is_enabled())
print("leaked:", ref() is not None)

This looks to be caused by value-recording uop (in the RECORD family) taking a strong reference to an object not being decref'd when traces are rewound

{
            _PyUOpInstruction *curr = uop_buffer_last(trace);
            while (curr->opcode != _SET_IP && uop_buffer_length(trace) > 2) {
                trace->next--;
                curr = uop_buffer_last(trace);
            }
            if (curr->opcode == _SET_IP) {
                int32_t old_target = (int32_t)uop_get_target(curr);
                curr->opcode = _DEOPT;
                curr->format = UOP_FORMAT_TARGET;
                curr->target = old_target;
            }
            goto done;
        }
CPython versions tested on:

CPython main branch

Operating systems tested on:

macOS

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

Start by running the supplied Python reproducer with the JIT enabled, then inspect the rewind loop shown in the report and the value-recording RECORD uops. Trace whether the recorded object is released when the trace is rewound; done means gc.collect() allows ref() to return None without regressing JIT behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, python
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.