Skip to content

Commit 73b4a74

Browse files
committed
Plug leak of strdup'ed strings in function_record, and enable test_methods_and_attributes and test_modules
1 parent b7f0370 commit 73b4a74

File tree

2 files changed

+32
-12
lines changed

2 files changed

+32
-12
lines changed

Diff for: .github/workflows/ci.yml

+1-4
Original file line numberDiff line numberDiff line change
@@ -225,12 +225,9 @@ jobs:
225225
--suppressions=tests/valgrind-misc.supp
226226
--gen-suppressions=all
227227
python -m pytest
228-
tests/test_multiple_inheritance.py
229-
tests/test_[abcdefhijklnop]*.py
228+
tests/test_[abcdefhijklmnopqrtuwxyz]*.py
230229
tests/test_sequences_and_iterators.py
231230
tests/test_stl.py
232-
tests/test_tagbased_polymorphic.py
233-
tests/test_union.py
234231
235232
236233
# # Testing on clang using the excellent silkeh clang docker images

Diff for: include/pybind11/pybind11.h

+31-8
Original file line numberDiff line numberDiff line change
@@ -224,21 +224,41 @@ class cpp_function : public function {
224224
}
225225
}
226226

227+
class strdup_guard {
228+
public:
229+
~strdup_guard() {
230+
for (auto s : strings)
231+
std::free(s);
232+
}
233+
char *operator()(const char *s) {
234+
auto t = strdup(s);
235+
strings.emplace_back(t);
236+
return t;
237+
}
238+
void release() {
239+
strings.clear();
240+
}
241+
private:
242+
std::vector<char *> strings;
243+
};
244+
227245
/// Register a function call with Python (generic non-templated code goes here)
228246
void initialize_generic(std::unique_ptr<detail::function_record> &&unique_rec, const char *text,
229247
const std::type_info *const *types, size_t args) {
230248
auto rec = unique_rec.get();
231249

250+
strdup_guard guarded_strdup;
251+
232252
/* Create copies of all referenced C-style strings */
233-
rec->name = strdup(rec->name ? rec->name : "");
234-
if (rec->doc) rec->doc = strdup(rec->doc);
253+
rec->name = guarded_strdup(rec->name ? rec->name : "");
254+
if (rec->doc) rec->doc = guarded_strdup(rec->doc);
235255
for (auto &a: rec->args) {
236256
if (a.name)
237-
a.name = strdup(a.name);
257+
a.name = guarded_strdup(a.name);
238258
if (a.descr)
239-
a.descr = strdup(a.descr);
259+
a.descr = guarded_strdup(a.descr);
240260
else if (a.value)
241-
a.descr = strdup(repr(a.value).cast<std::string>().c_str());
261+
a.descr = guarded_strdup(repr(a.value).cast<std::string>().c_str());
242262
}
243263

244264
rec->is_constructor = !strcmp(rec->name, "__init__") || !strcmp(rec->name, "__setstate__");
@@ -321,13 +341,13 @@ class cpp_function : public function {
321341
#if PY_MAJOR_VERSION < 3
322342
if (strcmp(rec->name, "__next__") == 0) {
323343
std::free(rec->name);
324-
rec->name = strdup("next");
344+
rec->name = guarded_strdup("next");
325345
} else if (strcmp(rec->name, "__bool__") == 0) {
326346
std::free(rec->name);
327-
rec->name = strdup("__nonzero__");
347+
rec->name = guarded_strdup("__nonzero__");
328348
}
329349
#endif
330-
rec->signature = strdup(signature.c_str());
350+
rec->signature = guarded_strdup(signature.c_str());
331351
rec->args.shrink_to_fit();
332352
rec->nargs = (std::uint16_t) args;
333353

@@ -361,6 +381,7 @@ class cpp_function : public function {
361381
capsule rec_capsule(unique_rec.release(), [](void *ptr) {
362382
destruct((detail::function_record *) ptr);
363383
});
384+
guarded_strdup.release();
364385

365386
object scope_module;
366387
if (rec->scope) {
@@ -396,12 +417,14 @@ class cpp_function : public function {
396417
rec->next = chain;
397418
auto rec_capsule = reinterpret_borrow<capsule>(((PyCFunctionObject *) m_ptr)->m_self);
398419
rec_capsule.set_pointer(unique_rec.release());
420+
guarded_strdup.release();
399421
} else {
400422
// Or end of chain (normal behavior)
401423
chain_start = chain;
402424
while (chain->next)
403425
chain = chain->next;
404426
chain->next = unique_rec.release();
427+
guarded_strdup.release();
405428
}
406429
}
407430

0 commit comments

Comments
 (0)