================ @@ -0,0 +1,187 @@ +/** + * When building shared libraries, hidden objects which are defined in header + * files will be duplicated, with one copy in each shared library. If the object + * was meant to be globally unique (one copy per program), this can cause very + * subtle bugs. This file contains tests for the -Wunique-object-duplication + * warning, which is meant to detect this. + * + * Roughly, an object might be incorrectly duplicated if: + * - Is defined in a header (so it might appear in multiple TUs), and + * - Has external linkage (otherwise it's supposed to be duplicated), and + * - Has hidden visibility (or else the dynamic linker will handle it) + * + * Duplication becomes an issue only if one of the following is true: + * - The object is mutable (the copies won't be in sync), or + * - Its initialization may has side effects (it may now run more than once), or + * - The value of its address is used. + * + * Currently, we only detect the first two, and only warn on effectful + * initialization if we're certain there are side effects. Warning if the + * address is taken is prone to false positives, so we don't warn for now. + * + * The check is also disabled on Windows for now, since it uses + * dllimport/dllexport instead of visibility. + */ + +#define HIDDEN __attribute__((visibility("hidden"))) +#define DEFAULT __attribute__((visibility("default"))) + +// Helper functions +constexpr int init_constexpr(int x) { return x; }; +extern double init_dynamic(int); + +/****************************************************************************** + * Case one: Static local variables in an externally-visible function + ******************************************************************************/ +namespace StaticLocalTest { + +inline void has_static_locals_external() { + // Mutable + static int disallowedStatic1 = 0; // hidden-warning {{'disallowedStatic1' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + // Initialization might run more than once + static const double disallowedStatic2 = disallowedStatic1++; // hidden-warning {{'disallowedStatic2' has hidden visibility, and external linkage; its initialization may run more than once when built into a shared library}} + + // OK, because immutable and compile-time-initialized + static constexpr int allowedStatic1 = 0; + static const float allowedStatic2 = 1; + static constexpr int allowedStatic3 = init_constexpr(2); + static const int allowedStatic4 = init_constexpr(3); +} + +// Don't warn for non-inline functions, since they can't (legally) appear +// in more than one TU in the first place. +void has_static_locals_non_inline() { + // Mutable + static int allowedStatic1 = 0; + // Initialization might run more than once + static const double allowedStatic2 = allowedStatic1++; +} + +// Everything in this function is OK because the function is TU-local +static void has_static_locals_internal() { + static int allowedStatic1 = 0; + static double allowedStatic2 = init_dynamic(2); + static char allowedStatic3 = []() { return allowedStatic1++; }(); + + static constexpr int allowedStatic4 = 0; + static const float allowedStatic5 = 1; + static constexpr int allowedStatic6 = init_constexpr(2); + static const int allowedStatic7 = init_constexpr(3); +} + +namespace { + +// Everything in this function is OK because the function is also TU-local +void has_static_locals_anon() { + static int allowedStatic1 = 0; + static double allowedStatic2 = init_dynamic(2); + static char allowedStatic3 = []() { return allowedStatic1++; }(); + + static constexpr int allowedStatic4 = 0; + static const float allowedStatic5 = 1; + static constexpr int allowedStatic6 = init_constexpr(2); + static const int allowedStatic7 = init_constexpr(3); +} + +} // Anonymous namespace + +HIDDEN inline void static_local_always_hidden() { + static int disallowedStatic1 = 3; // hidden-warning {{'disallowedStatic1' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + // expected-warning@-1 {{'disallowedStatic1' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + { + static int disallowedStatic2 = 3; // hidden-warning {{'disallowedStatic2' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + // expected-warning@-1 {{'disallowedStatic2' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + } + + auto lmb = []() { + static int disallowedStatic3 = 3; // hidden-warning {{'disallowedStatic3' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + // expected-warning@-1 {{'disallowedStatic3' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + }; +} + +DEFAULT void static_local_never_hidden() { + static int allowedStatic1 = 3; + + { + static int allowedStatic2 = 3; + } + + auto lmb = []() { + static int allowedStatic3 = 3; + }; +} + +// Don't warn on this because it's not in a function +const int setByLambda = ([]() { static int x = 3; return x++; })(); + +inline void has_extern_local() { + extern int allowedAddressExtern; // Not a definition +} + +inline void has_regular_local() { + int allowedAddressLocal = 0; +} + +inline void has_thread_local() { + // thread_local variables are static by default + thread_local int disallowedThreadLocal = 0; // hidden-warning {{'disallowedThreadLocal' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} +} + +} // namespace StaticLocalTest + +/****************************************************************************** + * Case two: Globals with external linkage + ******************************************************************************/ +namespace GlobalTest { + // Mutable + inline float disallowedGlobal1 = 3.14; // hidden-warning {{'disallowedGlobal1' is mutable, has hidden visibility, and external linkage; it may be duplicated when built into a shared library}} + // Same as above, but explicitly marked inline ---------------- DKLoehr wrote:
You're right, it was a holdover from an earlier version of the tests. Removed. https://github.com/llvm/llvm-project/pull/117622 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits