Skip to content

Commit 1dc9900

Browse files
committed
Avoid dynamic allocation and non-trivial destruction
... by using an std::array for the slots.
1 parent 335d8d4 commit 1dc9900

File tree

2 files changed

+26
-13
lines changed

2 files changed

+26
-13
lines changed

include/pybind11/detail/common.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -447,16 +447,16 @@ PYBIND11_WARNING_PUSH
447447
PYBIND11_WARNING_DISABLE_CLANG("-Wgnu-zero-variadic-macro-arguments")
448448
#define PYBIND11_MODULE(name, variable, ...) \
449449
static ::pybind11::module_::module_def PYBIND11_CONCAT(pybind11_module_def_, name); \
450-
static std::vector<PyModuleDef_Slot> PYBIND11_CONCAT(pybind11_module_slots_, name); \
450+
static ::pybind11::module_::slots_array PYBIND11_CONCAT(pybind11_module_slots_, name); \
451451
static int PYBIND11_CONCAT(pybind11_exec_, name)(PyObject *); \
452452
static void PYBIND11_CONCAT(pybind11_init_, name)(::pybind11::module_ &); \
453453
PYBIND11_PLUGIN_IMPL(name) { \
454454
PYBIND11_CHECK_PYTHON_VERSION \
455455
PYBIND11_ENSURE_INTERNALS_READY \
456456
auto &slots = PYBIND11_CONCAT(pybind11_module_slots_, name); \
457-
slots.clear(); \
458-
slots.emplace_back(PyModuleDef_Slot{ \
459-
Py_mod_exec, reinterpret_cast<void *>(&PYBIND11_CONCAT(pybind11_exec_, name))}); \
457+
slots[0] \
458+
= {Py_mod_exec, reinterpret_cast<void *>(&PYBIND11_CONCAT(pybind11_exec_, name))}; \
459+
slots[1] = {0, nullptr}; \
460460
auto m = ::pybind11::module_::initialize_multiphase_module_def( \
461461
PYBIND11_TOSTRING(name), \
462462
nullptr, \

include/pybind11/pybind11.h

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,33 +1406,46 @@ class module_ : public object {
14061406
return reinterpret_borrow<module_>(m);
14071407
}
14081408

1409+
/// Must be a POD type, and must hold enough entries for all of the possible slots PLUS ONE for
1410+
/// the sentinel (0) end slot.
1411+
using slots_array = std::array<PyModuleDef_Slot, 4>;
1412+
14091413
/** \rst
14101414
Initialized a module def for use with multi-phase module initialization.
14111415
14121416
``def`` should point to a statically allocated module_def.
14131417
``slots`` must already contain a Py_mod_exec or Py_mod_create slot and will be filled with
1414-
additional slots (and the empty terminator slot) from the supplied options.
1418+
additional slots from the supplied options (and the empty sentinel slot).
14151419
\endrst */
14161420
template <typename... Options>
14171421
static object initialize_multiphase_module_def(const char *name,
14181422
const char *doc,
14191423
module_def *def,
1420-
std::vector<PyModuleDef_Slot> &slots,
1424+
slots_array &slots,
14211425
Options &&...options) {
1422-
// remove zero end sentinel, if present
1423-
while (!slots.empty() && slots.back().slot == 0) {
1424-
slots.pop_back();
1426+
size_t next_slot = 0;
1427+
size_t term_slot = slots.size() - 1;
1428+
1429+
// find the end of the supplied slots
1430+
while (next_slot < term_slot && slots[next_slot].slot != 0) {
1431+
++next_slot;
14251432
}
14261433

14271434
bool nogil PYBIND11_MAYBE_UNUSED = detail::gil_not_used_option(options...);
14281435
if (nogil) {
14291436
#if defined(Py_mod_gil) && defined(Py_GIL_DISABLED)
1430-
slots.emplace_back(PyModuleDef_Slot{Py_mod_gil, Py_MOD_GIL_NOT_USED});
1437+
if (next_slot >= term_slot) {
1438+
pybind11_fail("initialize_multiphase_module_def: not enough space in slots");
1439+
}
1440+
slots[next_slot++] = {Py_mod_gil, Py_MOD_GIL_NOT_USED});
14311441
#endif
14321442
}
14331443

1434-
// must have a zero end sentinel
1435-
slots.emplace_back(PyModuleDef_Slot{0, nullptr});
1444+
// slots must have a zero end sentinel
1445+
if (next_slot > term_slot) {
1446+
pybind11_fail("initialize_multiphase_module_def: not enough space in slots");
1447+
}
1448+
slots[next_slot++] = {0, nullptr};
14361449

14371450
// module_def is PyModuleDef
14381451
// Placement new (not an allocation).
@@ -1442,7 +1455,7 @@ class module_ : public object {
14421455
/* m_doc */ options::show_user_defined_docstrings() ? doc : nullptr,
14431456
/* m_size */ 0,
14441457
/* m_methods */ nullptr,
1445-
/* m_slots */ slots.data(),
1458+
/* m_slots */ &slots[0],
14461459
/* m_traverse */ nullptr,
14471460
/* m_clear */ nullptr,
14481461
/* m_free */ nullptr};

0 commit comments

Comments
 (0)