1.. title:: clang-tidy - misc-coroutine-hostile-raii 2 3misc-coroutine-hostile-raii 4=========================== 5 6Detects when objects of certain hostile RAII types persists across suspension 7points in a coroutine. Such hostile types include scoped-lockable types and 8types belonging to a configurable denylist. 9 10Some objects require that they be destroyed on the same thread that created them. 11Traditionally this requirement was often phrased as "must be a local variable", 12under the assumption that local variables always work this way. However this is 13incorrect with C++20 coroutines, since an intervening ``co_await`` may cause the 14coroutine to suspend and later be resumed on another thread. 15 16The lifetime of an object that requires being destroyed on the same thread must 17not encompass a ``co_await`` or ``co_yield`` point. If you create/destroy an object, 18you must do so without allowing the coroutine to suspend in the meantime. 19 20Following types are considered as hostile: 21 22 - Scoped-lockable types: A scoped-lockable object persisting across a suspension 23 point is problematic as the lock held by this object could be unlocked by a 24 different thread. This would be undefined behaviour. 25 This includes all types annotated with the ``scoped_lockable`` attribute. 26 27 - Types belonging to a configurable denylist. 28 29.. code-block:: c++ 30 31 // Call some async API while holding a lock. 32 task coro() { 33 const std::lock_guard l(&mu_); 34 35 // Oops! The async Bar function may finish on a different 36 // thread from the one that created the lock_guard (and called 37 // Mutex::Lock). After suspension, Mutex::Unlock will be called on the wrong thread. 38 co_await Bar(); 39 } 40 41Options 42------- 43 44.. option:: RAIITypesList 45 46 A semicolon-separated list of qualified types which should not be allowed to 47 persist across suspension points. 48 Eg: ``my::lockable; a::b;::my::other::lockable;`` 49 The default value of this option is `"std::lock_guard;std::scoped_lock"`. 50 51.. option:: AllowedAwaitablesList 52 53 A semicolon-separated list of qualified types of awaitables types which can 54 be safely awaited while having hostile RAII objects in scope. 55 56 ``co_await``-ing an expression of ``awaitable`` type is considered 57 safe if the ``awaitable`` type is part of this list. 58 RAII objects persisting across such a ``co_await`` expression are 59 considered safe and hence are not flagged. 60 61 Example usage: 62 63 .. code-block:: c++ 64 65 // Consider option AllowedAwaitablesList = "safe_awaitable" 66 struct safe_awaitable { 67 bool await_ready() noexcept { return false; } 68 void await_suspend(std::coroutine_handle<>) noexcept {} 69 void await_resume() noexcept {} 70 }; 71 auto wait() { return safe_awaitable{}; } 72 73 task coro() { 74 // This persists across both the co_await's but is not flagged 75 // because the awaitable is considered safe to await on. 76 const std::lock_guard l(&mu_); 77 co_await safe_awaitable{}; 78 co_await wait(); 79 } 80 81 Eg: ``my::safe::awaitable;other::awaitable`` 82 The default value of this option is empty string `""`. 83 84