Skip to content

Commit 3aa82d1

Browse files
committed
Plug leaking function_record objects when exceptions are thrown
1 parent b7dfe5c commit 3aa82d1

File tree

1 file changed

+10
-8
lines changed

1 file changed

+10
-8
lines changed

include/pybind11/pybind11.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,8 @@ class cpp_function : public function {
115115

116116
protected:
117117
/// Space optimization: don't inline this frequently instantiated fragment
118-
PYBIND11_NOINLINE detail::function_record *make_function_record() {
119-
return new detail::function_record();
118+
PYBIND11_NOINLINE std::unique_ptr<detail::function_record> make_function_record() {
119+
return std::unique_ptr<detail::function_record>(new detail::function_record());
120120
}
121121

122122
/// Special internal constructor for functors, lambda functions, etc.
@@ -126,7 +126,8 @@ class cpp_function : public function {
126126
struct capture { remove_reference_t<Func> f; };
127127

128128
/* Store the function including any extra state it might have (e.g. a lambda capture object) */
129-
auto rec = make_function_record();
129+
auto unique_rec = make_function_record();
130+
auto rec = unique_rec.get();
130131

131132
/* Store the capture object directly in the function record if there is enough space */
132133
if (sizeof(capture) <= sizeof(rec->data)) {
@@ -207,7 +208,7 @@ class cpp_function : public function {
207208
PYBIND11_DESCR_CONSTEXPR auto types = decltype(signature)::types();
208209

209210
/* Register the function with Python from generic (non-templated) code */
210-
initialize_generic(rec, signature.text, types.data(), sizeof...(Args));
211+
initialize_generic(std::move(unique_rec), signature.text, types.data(), sizeof...(Args));
211212

212213
if (cast_in::has_args) rec->has_args = true;
213214
if (cast_in::has_kwargs) rec->has_kwargs = true;
@@ -224,8 +225,9 @@ class cpp_function : public function {
224225
}
225226

226227
/// Register a function call with Python (generic non-templated code goes here)
227-
void initialize_generic(detail::function_record *rec, const char *text,
228+
void initialize_generic(std::unique_ptr<detail::function_record> &&unique_rec, const char *text,
228229
const std::type_info *const *types, size_t args) {
230+
auto rec = unique_rec.get();
229231

230232
/* Create copies of all referenced C-style strings */
231233
rec->name = strdup(rec->name ? rec->name : "");
@@ -356,7 +358,7 @@ class cpp_function : public function {
356358
rec->def->ml_meth = reinterpret_cast<PyCFunction>(reinterpret_cast<void (*) (void)>(*dispatcher));
357359
rec->def->ml_flags = METH_VARARGS | METH_KEYWORDS;
358360

359-
capsule rec_capsule(rec, [](void *ptr) {
361+
capsule rec_capsule(unique_rec.release(), [](void *ptr) {
360362
destruct((detail::function_record *) ptr);
361363
});
362364

@@ -393,13 +395,13 @@ class cpp_function : public function {
393395
chain_start = rec;
394396
rec->next = chain;
395397
auto rec_capsule = reinterpret_borrow<capsule>(((PyCFunctionObject *) m_ptr)->m_self);
396-
rec_capsule.set_pointer(rec);
398+
rec_capsule.set_pointer(unique_rec.release());
397399
} else {
398400
// Or end of chain (normal behavior)
399401
chain_start = chain;
400402
while (chain->next)
401403
chain = chain->next;
402-
chain->next = rec;
404+
chain->next = unique_rec.release();
403405
}
404406
}
405407

0 commit comments

Comments
 (0)