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   t.detached = detached;
27   t.args = args;
28 }
29 
30 ThreadArgRetval::Args ThreadArgRetval::GetArgs(uptr thread) const {
31   __sanitizer::Lock lock(&mtx_);
32   auto t = data_.find(thread);
33   CHECK(t);
34   if (t->second.done)
35     return {};
36   return t->second.args;
37 }
38 
39 void ThreadArgRetval::Finish(uptr thread, void* retval) {
40   __sanitizer::Lock lock(&mtx_);
41   auto t = data_.find(thread);
42   if (!t)
43     return;
44   if (t->second.detached) {
45     // Retval of detached thread connot be retrieved.
46     data_.erase(t);
47     return;
48   }
49   t->second.done = true;
50   t->second.args.arg_retval = retval;
51 }
52 
53 u32 ThreadArgRetval::BeforeJoin(uptr thread) const {
54   __sanitizer::Lock lock(&mtx_);
55   auto t = data_.find(thread);
56   CHECK(t);
57   CHECK(!t->second.detached);
58   return t->second.gen;
59 }
60 
61 void ThreadArgRetval::AfterJoin(uptr thread, u32 gen) {
62   __sanitizer::Lock lock(&mtx_);
63   auto t = data_.find(thread);
64   if (!t || gen != t->second.gen) {
65     // Thread was reused and erased by any other event.
66     return;
67   }
68   CHECK(!t->second.detached);
69   data_.erase(t);
70 }
71 
72 void ThreadArgRetval::DetachLocked(uptr thread) {
73   CheckLocked();
74   auto t = data_.find(thread);
75   CHECK(t);
76   CHECK(!t->second.detached);
77   if (t->second.done) {
78     // We can't retrive retval after detached thread finished.
79     data_.erase(t);
80     return;
81   }
82   t->second.detached = true;
83 }
84 
85 void ThreadArgRetval::GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs) {
86   CheckLocked();
87   CHECK(ptrs);
88   data_.forEach([&](DenseMap<uptr, Data>::value_type& kv) -> bool {
89     ptrs->push_back((uptr)kv.second.args.arg_retval);
90     return true;
91   });
92 }
93 
94 }  // namespace __sanitizer
95