Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leak of locks from multiprocessing.Process #87311

Open
bstaletic mannequin opened this issue Feb 6, 2021 · 4 comments
Open

Leak of locks from multiprocessing.Process #87311

bstaletic mannequin opened this issue Feb 6, 2021 · 4 comments
Labels
3.11 only security fixes topic-C-API topic-multiprocessing type-bug An unexpected behavior, bug, or error

Comments

@bstaletic
Copy link
Mannequin

bstaletic mannequin commented Feb 6, 2021

BPO 43145
Nosy @pitrou, @applio, @shihai1991, @YannickJadoul, @bstaletic
Files
  • log: valgrind output
  • valgrind output.txt
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = None
    created_at = <Date 2021-02-06.13:02:37.289>
    labels = ['expert-C-API', '3.11', 'performance']
    title = 'Leak of locks from multiprocessing.Process'
    updated_at = <Date 2021-07-24.07:52:25.721>
    user = 'https://github.com/bstaletic'

    bugs.python.org fields:

    activity = <Date 2021-07-24.07:52:25.721>
    actor = 'shihai1991'
    assignee = 'none'
    closed = False
    closed_date = None
    closer = None
    components = ['C API']
    creation = <Date 2021-02-06.13:02:37.289>
    creator = 'bstaletic'
    dependencies = []
    files = ['49793', '50177']
    hgrepos = []
    issue_num = 43145
    keywords = []
    message_count = 4.0
    messages = ['386558', '386559', '386774', '398121']
    nosy_count = 5.0
    nosy_names = ['pitrou', 'davin', 'shihai1991', 'YannickJadoul', 'bstaletic']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = None
    status = 'open'
    superseder = None
    type = 'resource usage'
    url = 'https://bugs.python.org/issue43145'
    versions = ['Python 3.11']

    @bstaletic
    Copy link
    Mannequin Author

    bstaletic mannequin commented Feb 6, 2021

    The following C code leaks 7 locks allocated with PyThread_allocate_lock:

    #include <Python.h>
    
    int main()
    {
    	Py_Initialize();
    	PyObject* multiprocessing = PyImport_ImportModule("multiprocessing");
    	PyObject* Process = PyObject_GetAttrString(multiprocessing, "Process");
    	PyObject* args = PyTuple_New(0);
    	PyObject* kw = PyDict_New();
    	PyDict_SetItemString(kw, "target", Process);
    
    	PyObject* p = PyObject_Call(Process, args, kw);
    	PyObject* start = PyObject_GetAttrString(p, "start");
    	PyObject* join = PyObject_GetAttrString(p, "join");
    
    	PyObject_CallNoArgs(start);
    	PyObject_CallNoArgs(join);
    
    	Py_DECREF(join);
    	Py_DECREF(start);
    	Py_DECREF(p);
    	Py_DECREF(kw);
    	Py_DECREF(args);
    	Py_DECREF(Process);
    	Py_DECREF(multiprocessing);
    	Py_Finalize();
    }

    The following locks are leaked:

    1. runtime->interpreters.mutex = PyThread_allocate_lock();
    2. runtime->xidregistry.mutex = PyThread_allocate_lock();
    3. runtime->main_thread = PyThread_get_thread_ident();
    4. https://github.com/python/cpython/blob/master/Python/ceval.c#L810
    5. https://github.com/python/cpython/blob/master/Python/import.c#L126
    6. and 7. https://github.com/python/cpython/blob/master/Modules/_threadmodule.c#L597

    In the attachment is valgrind's output.

    @bstaletic bstaletic mannequin added 3.9 only security fixes 3.10 only security fixes topic-C-API performance Performance or resource usage labels Feb 6, 2021
    @bstaletic
    Copy link
    Mannequin Author

    bstaletic mannequin commented Feb 6, 2021

    Slightly simpler C example:

    #include <Python.h>
    
    int main()
    {
    	Py_Initialize();
    	PyObject* multiprocessing = PyImport_ImportModule("multiprocessing");
    	PyObject* Process = PyObject_GetAttrString(multiprocessing, "Process");
    
    	PyObject* p = PyObject_CallNoArgs(Process);
    	PyObject* start = PyObject_GetAttrString(p, "start");
    	PyObject* join = PyObject_GetAttrString(p, "join");
    
    	Py_DECREF(PyObject_CallNoArgs(start));
    	Py_DECREF(PyObject_CallNoArgs(join));
    
    	Py_DECREF(join);
    	Py_DECREF(start);
    	Py_DECREF(p);
    	Py_DECREF(Process);
    	Py_DECREF(multiprocessing);
    	Py_Finalize();
    }

    @gpshead gpshead changed the title Leak of locks in a subprocess Leak of locks from multiprocessing.Process Feb 10, 2021
    @bstaletic
    Copy link
    Mannequin Author

    bstaletic mannequin commented Feb 10, 2021

    The multiprocessing.Process, on Linux, ends up doing something like this:

    pid = os.fork()
    if pid == 0: os._exit()

    Translated to C:

    int main() {
        Py_Initialize();
        PyOS_BeforeFork();
        pid_t pid = fork();
        if (pid == 0) {
            PyOS_AfterFork_Child(); // Reinitializes stuff.
            _exit(0); // Child process exits without cleanup.
        }
        PyOS_AfterFork_Parent();
        Py_Finalize();
    }

    The call to _exit() happens in Lib/multiprocessing/popen_fork.py#L73

    My attempts at cleaning this up resulted in even more problems.

    @shihai1991
    Copy link
    Member

    The following locks are leaked:

    1. runtime->interpreters.mutex = PyThread_allocate_lock();
    2. runtime->xidregistry.mutex = PyThread_allocate_lock();
    3. runtime->main_thread = PyThread_get_thread_ident();
    4. https://github.com/python/cpython/blob/master/Python/ceval.c#L810
    5. https://github.com/python/cpython/blob/master/Python/import.c#L126
    6. and 7. https://github.com/python/cpython/blob/master/Modules/_threadmodule.c#L597

    Hi, Boris. Thanks for your report. We may receive the wrong alarm sometimes when we use valgrind.

    1. runtime->interpreters.mutex = PyThread_allocate_lock();

      free in here:
      FREE_LOCK(runtime->interpreters.mutex);
    2. https://github.com/python/cpython/blob/main/Python/ceval.c#L741
      free in here:
      PyInterpreterState_Delete(PyInterpreterState *interp)
    3. import_lock = PyThread_allocate_lock();
    4. free in here:
      PyThread_release_lock(import_lock);
    5. self->lock_lock = PyThread_allocate_lock();

      free in here:
      tp->tp_free((PyObject*)self);

      To tihs refleak, I can't get the entire traceback of newobject. But I haven't get refleak when I run ./python -m test _test_multiprocessing -R 3:3 -vv.

    @shihai1991 shihai1991 added 3.11 only security fixes and removed 3.9 only security fixes 3.10 only security fixes labels Jul 24, 2021
    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    @iritkatriel iritkatriel added type-bug An unexpected behavior, bug, or error and removed performance Performance or resource usage labels Sep 9, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.11 only security fixes topic-C-API topic-multiprocessing type-bug An unexpected behavior, bug, or error
    Projects
    Status: No status
    Development

    No branches or pull requests

    3 participants