1 //===-- sanitizer_thread_arg_retval.cpp -------------------------*- 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 #include "sanitizer_thread_arg_retval.h" 15 16 #include "sanitizer_placement_new.h" 17 18 namespace __sanitizer { 19 20 void ThreadArgRetval::CreateLocked(uptr thread, bool detached, 21 const Args& args) { 22 CheckLocked(); 23 Data& t = data_[thread]; 24 t = {}; 25 t.gen = gen_++; 26 static_assert(sizeof(gen_) == sizeof(u32) && kInvalidGen == UINT32_MAX); 27 if (gen_ == kInvalidGen) 28 gen_ = 0; 29 t.detached = detached; 30 t.args = args; 31 } 32 33 ThreadArgRetval::Args ThreadArgRetval::GetArgs(uptr thread) const { 34 __sanitizer::Lock lock(&mtx_); 35 auto t = data_.find(thread); 36 CHECK(t); 37 if (t->second.done) 38 return {}; 39 return t->second.args; 40 } 41 42 void ThreadArgRetval::Finish(uptr thread, void* retval) { 43 __sanitizer::Lock lock(&mtx_); 44 auto t = data_.find(thread); 45 if (!t) 46 return; 47 if (t->second.detached) { 48 // Retval of detached thread connot be retrieved. 49 data_.erase(t); 50 return; 51 } 52 t->second.done = true; 53 t->second.args.arg_retval = retval; 54 } 55 56 u32 ThreadArgRetval::BeforeJoin(uptr thread) const { 57 __sanitizer::Lock lock(&mtx_); 58 auto t = data_.find(thread); 59 if (t && !t->second.detached) { 60 return t->second.gen; 61 } 62 if (!common_flags()->detect_invalid_join) 63 return kInvalidGen; 64 const char* reason = "unknown"; 65 if (!t) { 66 reason = "already joined"; 67 } else if (t->second.detached) { 68 reason = "detached"; 69 } 70 Report("ERROR: %s: Joining %s thread, aborting.\n", SanitizerToolName, 71 reason); 72 Die(); 73 } 74 75 void ThreadArgRetval::AfterJoin(uptr thread, u32 gen) { 76 __sanitizer::Lock lock(&mtx_); 77 auto t = data_.find(thread); 78 if (!t || gen != t->second.gen) { 79 // Thread was reused and erased by any other event, or we had an invalid 80 // join. 81 return; 82 } 83 CHECK(!t->second.detached); 84 data_.erase(t); 85 } 86 87 void ThreadArgRetval::DetachLocked(uptr thread) { 88 CheckLocked(); 89 auto t = data_.find(thread); 90 CHECK(t); 91 CHECK(!t->second.detached); 92 if (t->second.done) { 93 // We can't retrive retval after detached thread finished. 94 data_.erase(t); 95 return; 96 } 97 t->second.detached = true; 98 } 99 100 void ThreadArgRetval::GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs) { 101 CheckLocked(); 102 CHECK(ptrs); 103 data_.forEach([&](DenseMap<uptr, Data>::value_type& kv) -> bool { 104 ptrs->push_back((uptr)kv.second.args.arg_retval); 105 return true; 106 }); 107 } 108 109 } // namespace __sanitizer 110