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

Linking problems with multiple translation units #37

Open
bitbugprime opened this issue Aug 26, 2020 · 1 comment
Open

Linking problems with multiple translation units #37

bitbugprime opened this issue Aug 26, 2020 · 1 comment

Comments

@bitbugprime
Copy link

bitbugprime commented Aug 26, 2020

The internal function contract_violation() shares the same function signature between two different versions, depending on whether TCB_SPAN_THROW_ON_CONTRACT_VIOLATION is defined.

This is no problem until multiple translation units are linked together and TCB_SPAN_THROW_ON_CONTRACT_VIOLATION is defined in some but not all of them. The linker chooses one of the definitions and throws away the other, which means that the translation units that turned on TCB_SPAN_THROW_ON_CONTRACT_VIOLATION can end up erroneously calling the std::terminate version if that is the one the linker chose. Or vice-versa I presume. I see this in debug builds using GCC 8 or 10.

You can fix this problem by giving the throwing version a different function signature. For example:
inline void contract_violation(const char* msg, int = 0)

It also seems to me that the throwing version should be [[noreturn]] like the std::terminate version, since it too never returns and [[noreturn]] because of throw was explicitly contemplated in many [[noreturn]] examples I've seen.

@tcbrindle
Copy link
Owner

This is no problem until multiple translation units are linked together and TCB_SPAN_THROW_ON_CONTRACT_VIOLATION is defined in some but not all of them.

Defining different contract checking settings in different TUs and linking them together is going to be an ODR violation whichever way you look at it, because various member functions will have different definitions. In practise you might get away with it because those member functions are very likely to be inlined, but it's still a bad idea. Like NDEBUG, TCB_SPAN_THROW_ON_CONTRACT_VIOLATION should be set at the project level, not per-TU.

It also seems to me that the throwing version should be [[noreturn]] like the std::terminate version

Yes, I agree.

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

No branches or pull requests

2 participants