I came across a curious bug today which I had somehow managed to avoid up until now.
file1.cpp:
#include <iostream>
inline void print() { std::cout << "Print1\n"; }
void y() { print(); }
file2.cpp:
#include <iostream>
inline void print() { std::cout << "Print2\n"; }
void x() { print(); }
main.cpp:
int x();
int y();
int main(){
x();
y();
}
Output:
Print1 (Expected Print2)
Print1
Because print()
has inline linkage, this produces no multiple definition error (compiled with g++ -Wall file1.cpp file2.cpp main.cpp
) and the duplicate symbol is silently collapsed. The actual case where I saw this was with inline class methods, not explicit inline functions, but the effect is the same.
I am wondering if there is a linker option or similar which will allow me to produce a warning when this type of error is made?
It isn't necessary/mandated that an error/warning be generated, by the standard. It is a violation of C++'s One Definition Rule, because of their having different function-bodies.
Quoting from: Extern Inlines by Default
The meaning of "extern inline" is that if calls to a function are not generated inline, then a compiler should make just one copy of the definition of the function, to be shared across all object files.
If the above occurs, that program's behavior is considered undefined according to the language standard, but that neither the compiler nor the linker is required to give a diagnostic message. In practice, this means that, depending on how the implementation works, the compiler or linker may just silently pick one of the definitions to be used everywhere.
The behaviour is consistent with GCC's definition of vague linkage here.
The functions are not internal linkage or in an anonymous namespace, so they're visibly external with the same name. They have different bodies so you've clearly violated the one definition rule. At that point any speculation as to what will happen isn't useful as your program is malformed.
I'm guessing that you compiled without optimization and the compiler generated function calls instead of actually inlining, and it picked one of the bodies to use as the function to call (leaving the other one orphaned). Now presumably if you compiled with optimization on, your expected output would be emitted but your program would still be incorrect.
EDIT for comment: Unfortunately it's not required for compilers to diagnose violations of the one definition rule (and they may not even be able to detect all cases). However there are a few things you can do:
static
or in an anonymous namespace (I prefer the namespace for logical grouping purposes but either is fine).inline
methods (regardless of location) as they tell the compiler explicitly that all versions will be identical (for non-inline methods you'll most likely at least get a duplicate symbol error from the linker). The safest approach here is to avoid global-namespace inline functions (or take particular care in your naming). Also you need to be really careful that changed #define
s don't change the function body (for example using assert
in an inline function where one use has NDEBUG
and the other doesn't).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With