Skip to content

PyModule_Create() and PyModule_Create2() can create flawed module objects #145132

@JakeSmarter

Description

@JakeSmarter

Bug report

Bug description:

$ python --version
Python 3.13.11

PyModule_Create() and PyModule_Create2() may return a flawed module object that crashes the interpreter because they make naive assumptions on PyModuleDef’s lifetime. Both functions must not make any assumptions on PyModuleDef’s lifetime and should not impose any lifetime requirements for a PyModuleDef instance on the caller. If the interpreter (or the module object) needs a PyModuleDef instance later on for it to work then PyModule_Create() and PyModule_Create2() should create a copy of it. Consider this simple example that places the PyModuleDef instance on the stack:

#include <Python.h>
PyMODINIT_FUNC PyInit_m(void) {
    PyModuleDef moduleDef = {0};
    moduleDef.m_base.ob_base.ob_refcnt = UINT_MAX;
    moduleDef.m_name = "m";
    moduleDef.m_doc  = PyDoc_STR("The “m” module");
    moduleDef.m_size = -1;
    PySys_FormatStdout("%s(): %u: moduleDef == %p\n", __func__, __LINE__, &moduleDef);
    PyObject* moduleObj = PyModule_Create(&moduleDef);
    PySys_FormatStdout("%s(): %u: moduleObj == %p\n", __func__, __LINE__, moduleObj);
    return moduleObj;
    /* Everything works fine until after return */
}

https://github.com/python/cpython/blob/3.13/Objects/moduleobject.c#L254 is probably where the nativity happens. PyModule_Create() and PyModule_Create2() naively store just a pointer to a PyModuleDef instance, which may become dangling at any time in the future. Although a PyModuleDef instance may share some resemblance with a Python object, it is not a GC managed Python object, where it might be enough to just increment the reference counter to hold on to it! Note also that PyModule_GetDef() is affected too because it may return a dangling pointer. Fixing PyModule_Create() and PyModule_Create2() may be easy but fixing PyModule_GetDef() is probably going to require changes to its semantics.

This issue may have been fixed in 3.15. I have not tested it. If so, can we expect this fix to be back ported to all currently supported Python versions?

CPython versions tested on:

3.13

Operating systems tested on:

Linux

Metadata

Metadata

Assignees

No one assigned

    Labels

    type-bugAn unexpected behavior, bug, or error

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions