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