1 //===-- sanitizer_thread_arg_retval.h ---------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is shared between sanitizer tools. 10 // 11 // Tracks thread arguments and return value for leak checking. 12 //===----------------------------------------------------------------------===// 13 14 #ifndef SANITIZER_THREAD_ARG_RETVAL_H 15 #define SANITIZER_THREAD_ARG_RETVAL_H 16 17 #include "sanitizer_common.h" 18 #include "sanitizer_dense_map.h" 19 #include "sanitizer_list.h" 20 #include "sanitizer_mutex.h" 21 22 namespace __sanitizer { 23 24 // Primary goal of the class is to keep alive arg and retval pointer for leak 25 // checking. However it can be used to pass those pointer into wrappers used by 26 // interceptors. The difference from ThreadRegistry/ThreadList is that this 27 // class keeps data up to the detach or join, as exited thread still can be 28 // joined to retrive retval. ThreadRegistry/ThreadList can discard exited 29 // threads immediately. 30 class SANITIZER_MUTEX ThreadArgRetval { 31 public: 32 struct Args { 33 void* (*routine)(void*); 34 void* arg_retval; // Either arg or retval. 35 }; 36 void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); } 37 void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); } 38 void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); } 39 40 // Wraps pthread_create or similar. We need to keep object locked, to 41 // prevent child thread from proceeding without thread handle. 42 template <typename CreateFn /* returns thread id on success, or 0 */> 43 void Create(bool detached, const Args& args, const CreateFn& fn) { 44 // No need to track detached threads with no args, but we will to do as it's 45 // not expensive and less edge-cases. 46 __sanitizer::Lock lock(&mtx_); 47 if (uptr thread = fn()) 48 CreateLocked(thread, detached, args); 49 } 50 51 // Returns thread arg and routine. 52 Args GetArgs(uptr thread) const; 53 54 // Mark thread as done and stores retval or remove if detached. Should be 55 // called by the thread. 56 void Finish(uptr thread, void* retval); 57 58 // Mark thread as detached or remove if done. 59 template <typename DetachFn /* returns true on success */> 60 void Detach(uptr thread, const DetachFn& fn) { 61 // Lock to prevent re-use of the thread between fn() and DetachLocked() 62 // calls. 63 __sanitizer::Lock lock(&mtx_); 64 if (fn()) 65 DetachLocked(thread); 66 } 67 68 // Joins the thread. 69 template <typename JoinFn /* returns true on success */> 70 void Join(uptr thread, const JoinFn& fn) { 71 // Remember internal id of the thread to prevent re-use of the thread 72 // between fn() and AfterJoin() calls. Locking JoinFn, like in 73 // Detach(), implementation can cause deadlock. 74 auto gen = BeforeJoin(thread); 75 if (fn()) 76 AfterJoin(thread, gen); 77 } 78 79 // Returns all arg and retval which are considered alive. 80 void GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs); 81 82 uptr size() const { 83 __sanitizer::Lock lock(&mtx_); 84 return data_.size(); 85 } 86 87 // FIXME: Add fork support. Expected users of the class are sloppy with forks 88 // anyway. We likely should lock/unlock the object to avoid deadlocks, and 89 // erase all but the current threads, so we can detect leaked arg or retval in 90 // child process. 91 92 // FIXME: Add cancelation support. Now if a thread was canceled, the class 93 // will keep pointers alive forever, missing leaks caused by cancelation. 94 95 private: 96 static const u32 kInvalidGen = UINT32_MAX; 97 struct Data { 98 Args args; 99 u32 gen; // Avoid collision if thread id re-used. 100 bool detached; 101 bool done; 102 }; 103 104 void CreateLocked(uptr thread, bool detached, const Args& args); 105 u32 BeforeJoin(uptr thread) const; 106 void AfterJoin(uptr thread, u32 gen); 107 void DetachLocked(uptr thread); 108 109 mutable Mutex mtx_; 110 111 DenseMap<uptr, Data> data_; 112 u32 gen_ = 0; 113 }; 114 115 } // namespace __sanitizer 116 117 #endif // SANITIZER_THREAD_ARG_RETVAL_H 118