1*c8dee2aaSAndroid Build Coastguard Worker /* 2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google LLC 3*c8dee2aaSAndroid Build Coastguard Worker * 4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be 5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file. 6*c8dee2aaSAndroid Build Coastguard Worker */ 7*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkNoDestructor_DEFINED 8*c8dee2aaSAndroid Build Coastguard Worker #define SkNoDestructor_DEFINED 9*c8dee2aaSAndroid Build Coastguard Worker 10*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef> 11*c8dee2aaSAndroid Build Coastguard Worker #include <new> 12*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits> // IWYU pragma: keep 13*c8dee2aaSAndroid Build Coastguard Worker #include <utility> 14*c8dee2aaSAndroid Build Coastguard Worker 15*c8dee2aaSAndroid Build Coastguard Worker // Helper type to create a function-local static variable of type `T` when `T` 16*c8dee2aaSAndroid Build Coastguard Worker // has a non-trivial destructor. Storing a `T` in a `SkNoDestructor<T>` will 17*c8dee2aaSAndroid Build Coastguard Worker // prevent `~T()` from running, even when the variable goes out of scope. This 18*c8dee2aaSAndroid Build Coastguard Worker // code is adapted from `base::NoDestructor<T>` in Chromium. 19*c8dee2aaSAndroid Build Coastguard Worker // 20*c8dee2aaSAndroid Build Coastguard Worker // Useful when a variable has static storage duration but its type has a 21*c8dee2aaSAndroid Build Coastguard Worker // non-trivial destructor. Chromium (and transitively, Skia) bans global 22*c8dee2aaSAndroid Build Coastguard Worker // constructors and destructors: using a function-local static variable prevents 23*c8dee2aaSAndroid Build Coastguard Worker // the former, while using `SkNoDestructor<T>` prevents the latter. 24*c8dee2aaSAndroid Build Coastguard Worker // 25*c8dee2aaSAndroid Build Coastguard Worker // ## Caveats 26*c8dee2aaSAndroid Build Coastguard Worker // 27*c8dee2aaSAndroid Build Coastguard Worker // - Must not be used for locals or fields; by definition, this does not run 28*c8dee2aaSAndroid Build Coastguard Worker // destructors, and this will likely lead to memory leaks and other 29*c8dee2aaSAndroid Build Coastguard Worker // surprising and undesirable behaviour. 30*c8dee2aaSAndroid Build Coastguard Worker // 31*c8dee2aaSAndroid Build Coastguard Worker // - If `T` is not constexpr constructible, must be a function-local static 32*c8dee2aaSAndroid Build Coastguard Worker // variable, since a global `NoDestructor<T>` will still generate a static 33*c8dee2aaSAndroid Build Coastguard Worker // initializer. 34*c8dee2aaSAndroid Build Coastguard Worker // 35*c8dee2aaSAndroid Build Coastguard Worker // - If `T` is constinit constructible, may be used as a global, but mark the 36*c8dee2aaSAndroid Build Coastguard Worker // global `constinit` (once C++20 is available) 37*c8dee2aaSAndroid Build Coastguard Worker // 38*c8dee2aaSAndroid Build Coastguard Worker // - If the data is rarely used, consider creating it on demand rather than 39*c8dee2aaSAndroid Build Coastguard Worker // caching it for the lifetime of the program. Though `SkNoDestructor<T>` 40*c8dee2aaSAndroid Build Coastguard Worker // does not heap allocate, the compiler still reserves space in bss for 41*c8dee2aaSAndroid Build Coastguard Worker // storing `T`, which costs memory at runtime. 42*c8dee2aaSAndroid Build Coastguard Worker // 43*c8dee2aaSAndroid Build Coastguard Worker // - If `T` is trivially destructible, do not use `SkNoDestructor<T>`: 44*c8dee2aaSAndroid Build Coastguard Worker // 45*c8dee2aaSAndroid Build Coastguard Worker // const uint64_t GetUnstableSessionSeed() { 46*c8dee2aaSAndroid Build Coastguard Worker // // No need to use `SkNoDestructor<T>` as `uint64_t` is trivially 47*c8dee2aaSAndroid Build Coastguard Worker // // destructible and does not require a global destructor. 48*c8dee2aaSAndroid Build Coastguard Worker // static const uint64_t kSessionSeed = GetRandUint64(); 49*c8dee2aaSAndroid Build Coastguard Worker // return kSessionSeed; 50*c8dee2aaSAndroid Build Coastguard Worker // } 51*c8dee2aaSAndroid Build Coastguard Worker // 52*c8dee2aaSAndroid Build Coastguard Worker // ## Example Usage 53*c8dee2aaSAndroid Build Coastguard Worker // 54*c8dee2aaSAndroid Build Coastguard Worker // const std::string& GetDefaultText() { 55*c8dee2aaSAndroid Build Coastguard Worker // // Required since `static const std::string` requires a global destructor. 56*c8dee2aaSAndroid Build Coastguard Worker // static const SkNoDestructor<std::string> s("Hello world!"); 57*c8dee2aaSAndroid Build Coastguard Worker // return *s; 58*c8dee2aaSAndroid Build Coastguard Worker // } 59*c8dee2aaSAndroid Build Coastguard Worker // 60*c8dee2aaSAndroid Build Coastguard Worker // More complex initialization using a lambda: 61*c8dee2aaSAndroid Build Coastguard Worker // 62*c8dee2aaSAndroid Build Coastguard Worker // const std::string& GetRandomNonce() { 63*c8dee2aaSAndroid Build Coastguard Worker // // `nonce` is initialized with random data the first time this function is 64*c8dee2aaSAndroid Build Coastguard Worker // // called, but its value is fixed thereafter. 65*c8dee2aaSAndroid Build Coastguard Worker // static const SkNoDestructor<std::string> nonce([] { 66*c8dee2aaSAndroid Build Coastguard Worker // std::string s(16); 67*c8dee2aaSAndroid Build Coastguard Worker // GetRandString(s.data(), s.size()); 68*c8dee2aaSAndroid Build Coastguard Worker // return s; 69*c8dee2aaSAndroid Build Coastguard Worker // }()); 70*c8dee2aaSAndroid Build Coastguard Worker // return *nonce; 71*c8dee2aaSAndroid Build Coastguard Worker // } 72*c8dee2aaSAndroid Build Coastguard Worker // 73*c8dee2aaSAndroid Build Coastguard Worker // ## Thread safety 74*c8dee2aaSAndroid Build Coastguard Worker // 75*c8dee2aaSAndroid Build Coastguard Worker // Initialization of function-local static variables is thread-safe since C++11. 76*c8dee2aaSAndroid Build Coastguard Worker // The standard guarantees that: 77*c8dee2aaSAndroid Build Coastguard Worker // 78*c8dee2aaSAndroid Build Coastguard Worker // - function-local static variables will be initialised the first time 79*c8dee2aaSAndroid Build Coastguard Worker // execution passes through the declaration. 80*c8dee2aaSAndroid Build Coastguard Worker // 81*c8dee2aaSAndroid Build Coastguard Worker // - if another thread's execution concurrently passes through the declaration 82*c8dee2aaSAndroid Build Coastguard Worker // in the middle of initialisation, that thread will wait for the in-progress 83*c8dee2aaSAndroid Build Coastguard Worker // initialisation to complete. 84*c8dee2aaSAndroid Build Coastguard Worker template <typename T> class SkNoDestructor { 85*c8dee2aaSAndroid Build Coastguard Worker public: 86*c8dee2aaSAndroid Build Coastguard Worker static_assert(!(std::is_trivially_constructible_v<T> && std::is_trivially_destructible_v<T>), 87*c8dee2aaSAndroid Build Coastguard Worker "T is trivially constructible and destructible; please use a constinit object of " 88*c8dee2aaSAndroid Build Coastguard Worker "type T directly instead"); 89*c8dee2aaSAndroid Build Coastguard Worker 90*c8dee2aaSAndroid Build Coastguard Worker static_assert(!std::is_trivially_destructible_v<T>, 91*c8dee2aaSAndroid Build Coastguard Worker "T is trivially destructible; please use a function-local static of type T " 92*c8dee2aaSAndroid Build Coastguard Worker "directly instead"); 93*c8dee2aaSAndroid Build Coastguard Worker 94*c8dee2aaSAndroid Build Coastguard Worker // Not constexpr; just write static constexpr T x = ...; if the value should be a constexpr. SkNoDestructor(Args &&...args)95*c8dee2aaSAndroid Build Coastguard Worker template <typename... Args> explicit SkNoDestructor(Args&&... args) { 96*c8dee2aaSAndroid Build Coastguard Worker new (fStorage) T(std::forward<Args>(args)...); 97*c8dee2aaSAndroid Build Coastguard Worker } 98*c8dee2aaSAndroid Build Coastguard Worker 99*c8dee2aaSAndroid Build Coastguard Worker // Allows copy and move construction of the contained type, to allow construction from an 100*c8dee2aaSAndroid Build Coastguard Worker // initializer list, e.g. for std::vector. SkNoDestructor(const T & x)101*c8dee2aaSAndroid Build Coastguard Worker explicit SkNoDestructor(const T& x) { new (fStorage) T(x); } SkNoDestructor(T && x)102*c8dee2aaSAndroid Build Coastguard Worker explicit SkNoDestructor(T&& x) { new (fStorage) T(std::move(x)); } 103*c8dee2aaSAndroid Build Coastguard Worker 104*c8dee2aaSAndroid Build Coastguard Worker SkNoDestructor(const SkNoDestructor&) = delete; 105*c8dee2aaSAndroid Build Coastguard Worker SkNoDestructor& operator=(const SkNoDestructor&) = delete; 106*c8dee2aaSAndroid Build Coastguard Worker 107*c8dee2aaSAndroid Build Coastguard Worker ~SkNoDestructor() = default; 108*c8dee2aaSAndroid Build Coastguard Worker 109*c8dee2aaSAndroid Build Coastguard Worker const T& operator*() const { return *get(); } 110*c8dee2aaSAndroid Build Coastguard Worker T& operator*() { return *get(); } 111*c8dee2aaSAndroid Build Coastguard Worker 112*c8dee2aaSAndroid Build Coastguard Worker const T* operator->() const { return get(); } 113*c8dee2aaSAndroid Build Coastguard Worker T* operator->() { return get(); } 114*c8dee2aaSAndroid Build Coastguard Worker get()115*c8dee2aaSAndroid Build Coastguard Worker const T* get() const { return reinterpret_cast<const T*>(fStorage); } get()116*c8dee2aaSAndroid Build Coastguard Worker T* get() { return reinterpret_cast<T*>(fStorage); } 117*c8dee2aaSAndroid Build Coastguard Worker 118*c8dee2aaSAndroid Build Coastguard Worker private: 119*c8dee2aaSAndroid Build Coastguard Worker alignas(T) std::byte fStorage[sizeof(T)]; 120*c8dee2aaSAndroid Build Coastguard Worker 121*c8dee2aaSAndroid Build Coastguard Worker #if defined(__clang__) && defined(__has_feature) 122*c8dee2aaSAndroid Build Coastguard Worker #if __has_feature(leak_sanitizer) || __has_feature(address_sanitizer) 123*c8dee2aaSAndroid Build Coastguard Worker // TODO(https://crbug.com/812277): This is a hack to work around the fact that LSan doesn't seem 124*c8dee2aaSAndroid Build Coastguard Worker // to treat SkNoDestructor as a root for reachability analysis. This means that code like this: 125*c8dee2aaSAndroid Build Coastguard Worker // static SkNoDestructor<std::vector<int>> v({1, 2, 3}); 126*c8dee2aaSAndroid Build Coastguard Worker // is considered a leak. Using the standard leak sanitizer annotations to suppress leaks doesn't 127*c8dee2aaSAndroid Build Coastguard Worker // work: std::vector is implicitly constructed before calling the SkNoDestructor constructor. 128*c8dee2aaSAndroid Build Coastguard Worker // 129*c8dee2aaSAndroid Build Coastguard Worker // Unfortunately, I haven't been able to demonstrate this issue in simpler reproductions: until 130*c8dee2aaSAndroid Build Coastguard Worker // that's resolved, hold an explicit pointer to the placement-new'd object in leak sanitizer 131*c8dee2aaSAndroid Build Coastguard Worker // mode to help LSan realize that objects allocated by the contained type are still reachable. 132*c8dee2aaSAndroid Build Coastguard Worker T* fStoragePtr = reinterpret_cast<T*>(fStorage); 133*c8dee2aaSAndroid Build Coastguard Worker #endif // leak_sanitizer/address_sanitizer 134*c8dee2aaSAndroid Build Coastguard Worker #endif // __has_feature 135*c8dee2aaSAndroid Build Coastguard Worker }; 136*c8dee2aaSAndroid Build Coastguard Worker 137*c8dee2aaSAndroid Build Coastguard Worker #endif // SkNoDestructor_DEFINED 138