Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add virtual destructor #12

Merged
merged 1 commit into from
Jun 6, 2024
Merged

Conversation

PhilMiller
Copy link
Member

@PhilMiller PhilMiller commented Apr 19, 2024

The Bmi base class definition needs to define its destructor as virtual to enable derived classes to support accurate destruction.

Cf https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-dtor

This is technically an ABI change impacting any existing code. To avoid potential failures and definite UB from ODR violation, all clients and implementations within a given system will need to be (re-) built against matching versions of this header.

It's unclear whether it's a breaking change of the BMI specification itself. The depends on whether the reference to this file is normative or exemplary.

Resolves #11

The Bmi base class definition needs to define its destructor as `virtual` to enable derived classes to support accurate destruction.

Cf https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rh-dtor

This is technically an ABI change impacting any existing code. To avoid potential failures and definite UB from ODR violation, all clients and implementations within a given system will need to be (re-) built against matching versions of this header.

It's unclear whether it's a breaking change of the BMI specification itself. The depends on whether the reference to this file is normative or exemplary.
@PhilMiller
Copy link
Member Author

The ABI change is probably not too consequential for most users. I'm roughly guessing that the sprawling set of components and large multi-team project of the NWM is going to be the worst impacted. It's also where I saw this come up, due to GCC's -Wdelete-non-virtual-dtor rightly flagging some object deletions as suspect.

@PhilMiller
Copy link
Member Author

@mdpiper What's the process look like for actually merging a change like this?

@mdpiper
Copy link
Member

mdpiper commented Apr 19, 2024

@PhilMiller I'd like someone with C++ knowledge to review this. Would you be able to recommend someone? After review, we should be able to merge this with lazy consensus.

@PhilMiller
Copy link
Member Author

@hellkite500 knows the relevant considerations on both the C++ and BMI sides well enough. We'd already discussed the patch before I posted it.

Otherwise, I could solicit someone working on the Kokkos Tools, I guess, as folks with ABI evolution constraints on a plugin system design.

From a strictly C++ development perspective, I think of this as an utterly mundane, uncontroversial change. The challenge as I see it is entirely from the BMI ecosystem consideration. In the long run, it should fix more bugs than it creates, but it has potential for extended 'short-term' pain as people get the message that they need to transition by rebuilding all their code with the revised header.

Copy link

@hellkite500 hellkite500 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is needed for proper destruction of subclasses of Bmi using dynamic dispatch to virtual functions through a Bmi base pointer. This is common practice in interface design/implementation using C++ .

In practice, I don't think too many implementations of C++ bmi models are going to be using custom destructors, so this probably hasn't been a problem. Typically "destruction" semantics are likely done in the Finalize function and implementers likely don't define custom destruction beyond that in many cases.

However, there may be use cases in which custom destruction semantics are used/needed, and without the virtual destructor, calls to a Bmi base pointer's destructor will only call the (default, do nothing) Bmi::~() and the subclass destructor won't get dispatched to at runtime.

Adding this does, as noted, introduce an ABI change for the C++ implementation only. There doesn't seem to be real consensus yet (see this disscussion thread) as to what level of ABI compatibility BMI should strive to maintain, both at the conceptual interface layer of BMI and at the individual implementations such as bmi-cxx. That said, I think a release tag documenting the change and the possible implications and fix (recompile components with new header) would likely be sufficient to communicate to users/developers.

@RolfHut tagging you here as you have expressed interest in the ABI compatibility, and may want to track this merge and re-build if you have C++ components in any workflows.

@mdpiper
Copy link
Member

mdpiper commented Apr 19, 2024

@PhilMiller I've tagged this lazy-consensus. If we don't get any cautionary comments, we can merge this next week.

@RolfHut
Copy link

RolfHut commented Apr 20, 2024

Can we get someone that worked on GRPC4BMI to also review this? As a PI I can not oversee the impact this has, it feels very specific to C++ and not to BMI in general, but this is beyond my knowlegde. Given that in GRPC4BMI we also work with C++, it might impact it. Maybe @nielsdrost can suggest who would be best for this?

@mdpiper
Copy link
Member

mdpiper commented Apr 26, 2024

@RolfHut @nielsdrost Would you still like someone from @eWaterCycle to look at this PR? If not, let me know & I'll merge it.

@RolfHut
Copy link

RolfHut commented Apr 27, 2024

yes I would, but personally I can not oversee the scope of this. Maybe @BSchilperoort or @Peter9192, but since they are both not in this org, I will email them. Please give a few days before laze merging.

@PhilMiller
Copy link
Member Author

@RolfHut Since this is such a touchy change, would it be possible to get comments affirming that they think this is OK? As eager as I am to see it move forward, the sort of breakage this can cause if people are caught unaware is really painful to debug, so I'd like to avoid that.

@Peter9192
Copy link

That said, I think a release tag documenting the change and the possible implications and fix (recompile components with new header) would likely be sufficient to communicate to users/developers

We haven't had time to look into this in detail, but a dedicated release tag would be great so we can always pin to v2.0 as a (temporary) workaround for unforeseen issues in the future.

@RolfHut
Copy link

RolfHut commented May 21, 2024

@mdpiper see @Peter9192 his comment, if you create that dedicated release tag, than all ok with us from eWaterCycle.

@goord
Copy link

goord commented May 29, 2024

yes I would, but personally I can not oversee the scope of this. Maybe @BSchilperoort or @Peter9192, but since they are both not in this org, I will email them. Please give a few days before laze merging.

In grpc4bmi we don't subclass the BMI C++ interface but we wrap it. This means the missing virtual keyword in the destructor doesn't affect this code and rebuilding e.g. containers with this correct destructor in place is trivial. I'm not sure whether we have C++ models in eWaterCycle that do any cleanup in the destructor (usually 'finalize' is used for that), if they did they would have suffered from a memory leak. Which is then fixed with this change.

@PhilMiller
Copy link
Member Author

Ok, it sounds like we've got good awareness among folks who are most likely to be affected, general support, and no objections. I think we're clear to merge, since I was the one asking us to be more stringent about affirmative responses to this change as opposed to lazy consensus.

@PhilMiller
Copy link
Member Author

@Peter9192 @RolfHut It looks like there are already tags in the repository v2.0 with the current code, and v2.0.1 and v2.0.2 with various CI and build system tweaks from that.

Since I believe the major version is meant to be kept aligned with the BMI standard itself, I'd suggest the tag with this change merged be name v2.1, or some beta/pre-release variant thereof.

@Peter9192
Copy link

Alternatively, if this is considered a bugfix then semantic versioning would specify to increase the patch number, i.e. v2.0.3. I don't have a strong opinion on this though, as long as the changes associated with each version are clearly described.

@PhilMiller
Copy link
Member Author

Strict application of SemVer would call this 3.0, due to the lack of compatibility. SemVer doesn't really address ABI issues separate from API, though. It also doesn't address alignment of a product with a standard specification

@PhilMiller
Copy link
Member Author

@mdpiper Would you like to press the Merge button? I'm feeling a bit too timid to do that myself as my first applied change here.

@mdpiper mdpiper merged commit 7c9a1d0 into csdms:master Jun 6, 2024
3 checks passed
@mdpiper
Copy link
Member

mdpiper commented Jun 6, 2024

@PhilMiller Let’s also start a discussion on the BMI forum about versioning. @mcflugen & I threw around some ideas a few years ago, but we weren’t happy with any of them. It might be nice to work on this again with more people involved.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Class Bmi has virtual member functions, but no virtual destructor
6 participants