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
CreateLocked(uptr thread,bool detached,const Args & args)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
GetArgs(uptr thread) const33 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
Finish(uptr thread,void * retval)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
BeforeJoin(uptr thread) const56 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
AfterJoin(uptr thread,u32 gen)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
DetachLocked(uptr thread)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
GetAllPtrsLocked(InternalMmapVector<uptr> * ptrs)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