From 79e9d43c1b8c1034afb2e8f5e9c1abb412ed1d70 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Wed, 24 Nov 2021 02:04:10 +0100 Subject: [PATCH] Disable broken default-generated copy ctor in C++ wrappers We can't rely on the default-generated copy ctor because it simply copies the (possibly) owned pointer, resulting in double destruction if it's ever used, so disable it completely unless it is explicitly declared in the original class, in which case we can wrap it using the C function wrapper defined for it. Note that we probably should also wrap default-generated copy ctor of the original class, if it has any, but currently we don't do it even at C wrappers level, and so can't do it for C++ wrappers neither. --- Source/Modules/c.cxx | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Source/Modules/c.cxx b/Source/Modules/c.cxx index b85e3336f..633e34558 100644 --- a/Source/Modules/c.cxx +++ b/Source/Modules/c.cxx @@ -300,6 +300,7 @@ public: ); class_node_ = n; + has_copy_ctor_ = false; } // Emit wrapper of a member function. @@ -450,6 +451,10 @@ public: classname, "{", wname, "(", parms_call.get(), ")} {}\n", NIL ); + + // Remember that we had a copy ctor. + if (Checkattr(n, "copy_constructor", "1")) + has_copy_ctor_ = true; } else if (Checkattr(n, "nodeType", "destructor")) { if (first_base_) { // Delete the pointer and reset the ownership flag to ensure that the base class doesn't do it again. @@ -549,6 +554,23 @@ public: Append(cxx_wrappers_.f_decls, " {}\n"); + // If the class doesn't have a copy ctor, forbid copying it: we currently must do it even if the original class has a perfectly cromulent implicit copy ctor + // because we don't wrap it and copying would use the trivial ctor that would just copy the swig_self_ pointer resulting in double destruction of it later. + // To fix this, we would need to always provide our own C wrapper for the copy ctor, which is not something we do currently. + if (!has_copy_ctor_) { + Printv(cxx_wrappers_.f_decls, + cindent, classname, "(", classname, " const&) = delete;\n", + NIL + ); + } + + // We currently never wrap the assignment operator, so we have to always disable it for the same reason we disable the copy ctor above. + // It would definitely be nice to provide the assignment, if possible. + Printv(cxx_wrappers_.f_decls, + cindent, classname, "& operator=(", classname, " const&) = delete;\n", + NIL + ); + // We also need a swig_self() method for accessing the C object pointer. Printv(cxx_wrappers_.f_decls, cindent, c_class_ptr.get(), " swig_self() const noexcept ", @@ -830,6 +852,9 @@ private: type_desc* ptype_desc_; type_desc* rtype_desc_; + // True if the class defines an explicit copy ctor. + bool has_copy_ctor_; + // Non copyable. cxx_class_wrapper(const cxx_class_wrapper&);