Skip to content

Commit d159a56

Browse files
authored
static allocation for PyModuleDef, to avoid leak check errors. (#2413)
* Initializing PyModuleDef object with PyModuleDef_HEAD_INIT. Python 3.8 documentation: m_base - Always initialize this member to PyModuleDef_HEAD_INIT. Long-standing (since first github commit in 2015), inconsequential bug. Also removing inconsequential Py_INCREF(def): PyModule_Create() resets the reference count to 1. * git rebase master * moving static PyModuleDef declaration to global scope, as requested by @wjakob * renaming the two new macros, to start with PYBIND11_DETAIL_MODULE
1 parent 3c7ef56 commit d159a56

File tree

2 files changed

+29
-10
lines changed

2 files changed

+29
-10
lines changed

include/pybind11/detail/common.h

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,13 +307,26 @@ extern "C" {
307307
});
308308
}
309309
\endrst */
310+
#if PY_MAJOR_VERSION >= 3
311+
#define PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \
312+
static PyModuleDef PYBIND11_CONCAT(pybind11_module_def_, name);
313+
#define PYBIND11_DETAIL_MODULE_CREATE(name) \
314+
auto m = pybind11::module( \
315+
PYBIND11_TOSTRING(name), nullptr, \
316+
&PYBIND11_CONCAT(pybind11_module_def_, name));
317+
#else
318+
#define PYBIND11_DETAIL_MODULE_STATIC_DEF(name)
319+
#define PYBIND11_DETAIL_MODULE_CREATE(name) \
320+
auto m = pybind11::module(PYBIND11_TOSTRING(name));
321+
#endif
310322
#define PYBIND11_MODULE(name, variable) \
323+
PYBIND11_DETAIL_MODULE_STATIC_DEF(name) \
311324
PYBIND11_MAYBE_UNUSED \
312325
static void PYBIND11_CONCAT(pybind11_init_, name)(pybind11::module &); \
313326
PYBIND11_PLUGIN_IMPL(name) { \
314327
PYBIND11_CHECK_PYTHON_VERSION \
315328
PYBIND11_ENSURE_INTERNALS_READY \
316-
auto m = pybind11::module(PYBIND11_TOSTRING(name)); \
329+
PYBIND11_DETAIL_MODULE_CREATE(name) \
317330
try { \
318331
PYBIND11_CONCAT(pybind11_init_, name)(m); \
319332
return m.ptr(); \

include/pybind11/pybind11.h

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -862,18 +862,24 @@ class module_ : public object {
862862
PYBIND11_OBJECT_DEFAULT(module_, object, PyModule_Check)
863863

864864
/// Create a new top-level Python module with the given name and docstring
865-
explicit module_(const char *name, const char *doc = nullptr) {
866-
if (!options::show_user_defined_docstrings()) doc = nullptr;
867865
#if PY_MAJOR_VERSION >= 3
868-
auto *def = new PyModuleDef();
869-
std::memset(def, 0, sizeof(PyModuleDef));
870-
def->m_name = name;
871-
def->m_doc = doc;
872-
def->m_size = -1;
873-
Py_INCREF(def);
866+
explicit module_(const char *name, const char *doc = nullptr, PyModuleDef *def = nullptr) {
867+
if (!def) def = new PyModuleDef();
868+
def = new (def) PyModuleDef { // Placement new (not an allocation).
869+
/* m_base */ PyModuleDef_HEAD_INIT,
870+
/* m_name */ name,
871+
/* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr,
872+
/* m_size */ -1,
873+
/* m_methods */ nullptr,
874+
/* m_slots */ nullptr,
875+
/* m_traverse */ nullptr,
876+
/* m_clear */ nullptr,
877+
/* m_free */ nullptr
878+
};
874879
m_ptr = PyModule_Create(def);
875880
#else
876-
m_ptr = Py_InitModule3(name, nullptr, doc);
881+
explicit module_(const char *name, const char *doc = nullptr) {
882+
m_ptr = Py_InitModule3(name, nullptr, options::show_user_defined_docstrings() ? doc : nullptr);
877883
#endif
878884
if (m_ptr == nullptr)
879885
pybind11_fail("Internal error in module_::module_()");

0 commit comments

Comments
 (0)