@@ -126,6 +126,7 @@ class cpp_function : public function {
126
126
struct capture { remove_reference_t <Func> f; };
127
127
128
128
/* Store the function including any extra state it might have (e.g. a lambda capture object) */
129
+ // The unique_ptr makes sure nothing is leaked in case of an exception.
129
130
auto unique_rec = make_function_record ();
130
131
auto rec = unique_rec.get ();
131
132
@@ -208,6 +209,7 @@ class cpp_function : public function {
208
209
PYBIND11_DESCR_CONSTEXPR auto types = decltype (signature)::types ();
209
210
210
211
/* Register the function with Python from generic (non-templated) code */
212
+ // Pass on the ownership over the `unique_rec` to `initialize_generic`. `rec` stays valid.
211
213
initialize_generic (std::move (unique_rec), signature.text , types.data (), sizeof ...(Args));
212
214
213
215
if (cast_in::has_args) rec->has_args = true ;
@@ -224,6 +226,8 @@ class cpp_function : public function {
224
226
}
225
227
}
226
228
229
+ // Utility class that keeps track of all duplicated strings, and cleans them up in its destructor,
230
+ // unless they are released. Basically a RAII-solution to deal with exceptions along the way.
227
231
class strdup_guard {
228
232
public:
229
233
~strdup_guard () {
@@ -247,6 +251,11 @@ class cpp_function : public function {
247
251
const std::type_info *const *types, size_t args) {
248
252
auto rec = unique_rec.get ();
249
253
254
+ // Keep track of strdup'ed strings, and clean them up as long as the function's capsule
255
+ // has not taken ownership yet (when `unique_rec.release()` is called).
256
+ // Note: This cannot easily be fixed by a `unique_ptr` with custom deleter, because the strings
257
+ // are only referenced before strdup'ing. So only *after* the following block could `destruct`
258
+ // safely be called, but even then, `repr` could still throw in the middle of copying all strings.
250
259
strdup_guard guarded_strdup;
251
260
252
261
/* Create copies of all referenced C-style strings */
0 commit comments