You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
The text was updated successfully, but these errors were encountered:
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
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.
The text was updated successfully, but these errors were encountered: