106c3fb27SDimitry Andric //===-- sanitizer_thread_arg_retval.cpp -------------------------*- C++ -*-===//
206c3fb27SDimitry Andric //
306c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
506c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606c3fb27SDimitry Andric //
706c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
806c3fb27SDimitry Andric //
906c3fb27SDimitry Andric // This file is shared between sanitizer tools.
1006c3fb27SDimitry Andric //
1106c3fb27SDimitry Andric // Tracks thread arguments and return value for leak checking.
1206c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
1306c3fb27SDimitry Andric 
1406c3fb27SDimitry Andric #include "sanitizer_thread_arg_retval.h"
1506c3fb27SDimitry Andric 
1606c3fb27SDimitry Andric #include "sanitizer_placement_new.h"
1706c3fb27SDimitry Andric 
1806c3fb27SDimitry Andric namespace __sanitizer {
1906c3fb27SDimitry Andric 
CreateLocked(uptr thread,bool detached,const Args & args)2006c3fb27SDimitry Andric void ThreadArgRetval::CreateLocked(uptr thread, bool detached,
2106c3fb27SDimitry Andric                                    const Args& args) {
2206c3fb27SDimitry Andric   CheckLocked();
2306c3fb27SDimitry Andric   Data& t = data_[thread];
2406c3fb27SDimitry Andric   t = {};
2506c3fb27SDimitry Andric   t.gen = gen_++;
26*297eecfbSDimitry Andric   static_assert(sizeof(gen_) == sizeof(u32) && kInvalidGen == UINT32_MAX);
27*297eecfbSDimitry Andric   if (gen_ == kInvalidGen)
28*297eecfbSDimitry Andric     gen_ = 0;
2906c3fb27SDimitry Andric   t.detached = detached;
3006c3fb27SDimitry Andric   t.args = args;
3106c3fb27SDimitry Andric }
3206c3fb27SDimitry Andric 
GetArgs(uptr thread) const3306c3fb27SDimitry Andric ThreadArgRetval::Args ThreadArgRetval::GetArgs(uptr thread) const {
3406c3fb27SDimitry Andric   __sanitizer::Lock lock(&mtx_);
3506c3fb27SDimitry Andric   auto t = data_.find(thread);
3606c3fb27SDimitry Andric   CHECK(t);
3706c3fb27SDimitry Andric   if (t->second.done)
3806c3fb27SDimitry Andric     return {};
3906c3fb27SDimitry Andric   return t->second.args;
4006c3fb27SDimitry Andric }
4106c3fb27SDimitry Andric 
Finish(uptr thread,void * retval)4206c3fb27SDimitry Andric void ThreadArgRetval::Finish(uptr thread, void* retval) {
4306c3fb27SDimitry Andric   __sanitizer::Lock lock(&mtx_);
4406c3fb27SDimitry Andric   auto t = data_.find(thread);
4506c3fb27SDimitry Andric   if (!t)
4606c3fb27SDimitry Andric     return;
4706c3fb27SDimitry Andric   if (t->second.detached) {
4806c3fb27SDimitry Andric     // Retval of detached thread connot be retrieved.
4906c3fb27SDimitry Andric     data_.erase(t);
5006c3fb27SDimitry Andric     return;
5106c3fb27SDimitry Andric   }
5206c3fb27SDimitry Andric   t->second.done = true;
5306c3fb27SDimitry Andric   t->second.args.arg_retval = retval;
5406c3fb27SDimitry Andric }
5506c3fb27SDimitry Andric 
BeforeJoin(uptr thread) const5606c3fb27SDimitry Andric u32 ThreadArgRetval::BeforeJoin(uptr thread) const {
5706c3fb27SDimitry Andric   __sanitizer::Lock lock(&mtx_);
5806c3fb27SDimitry Andric   auto t = data_.find(thread);
59*297eecfbSDimitry Andric   if (t && !t->second.detached) {
6006c3fb27SDimitry Andric     return t->second.gen;
6106c3fb27SDimitry Andric   }
62*297eecfbSDimitry Andric   if (!common_flags()->detect_invalid_join)
63*297eecfbSDimitry Andric     return kInvalidGen;
64*297eecfbSDimitry Andric   const char* reason = "unknown";
65*297eecfbSDimitry Andric   if (!t) {
66*297eecfbSDimitry Andric     reason = "already joined";
67*297eecfbSDimitry Andric   } else if (t->second.detached) {
68*297eecfbSDimitry Andric     reason = "detached";
69*297eecfbSDimitry Andric   }
70*297eecfbSDimitry Andric   Report("ERROR: %s: Joining %s thread, aborting.\n", SanitizerToolName,
71*297eecfbSDimitry Andric          reason);
72*297eecfbSDimitry Andric   Die();
73*297eecfbSDimitry Andric }
7406c3fb27SDimitry Andric 
AfterJoin(uptr thread,u32 gen)7506c3fb27SDimitry Andric void ThreadArgRetval::AfterJoin(uptr thread, u32 gen) {
7606c3fb27SDimitry Andric   __sanitizer::Lock lock(&mtx_);
7706c3fb27SDimitry Andric   auto t = data_.find(thread);
7806c3fb27SDimitry Andric   if (!t || gen != t->second.gen) {
79*297eecfbSDimitry Andric     // Thread was reused and erased by any other event, or we had an invalid
80*297eecfbSDimitry Andric     // join.
8106c3fb27SDimitry Andric     return;
8206c3fb27SDimitry Andric   }
8306c3fb27SDimitry Andric   CHECK(!t->second.detached);
8406c3fb27SDimitry Andric   data_.erase(t);
8506c3fb27SDimitry Andric }
8606c3fb27SDimitry Andric 
DetachLocked(uptr thread)8706c3fb27SDimitry Andric void ThreadArgRetval::DetachLocked(uptr thread) {
8806c3fb27SDimitry Andric   CheckLocked();
8906c3fb27SDimitry Andric   auto t = data_.find(thread);
9006c3fb27SDimitry Andric   CHECK(t);
9106c3fb27SDimitry Andric   CHECK(!t->second.detached);
9206c3fb27SDimitry Andric   if (t->second.done) {
9306c3fb27SDimitry Andric     // We can't retrive retval after detached thread finished.
9406c3fb27SDimitry Andric     data_.erase(t);
9506c3fb27SDimitry Andric     return;
9606c3fb27SDimitry Andric   }
9706c3fb27SDimitry Andric   t->second.detached = true;
9806c3fb27SDimitry Andric }
9906c3fb27SDimitry Andric 
GetAllPtrsLocked(InternalMmapVector<uptr> * ptrs)10006c3fb27SDimitry Andric void ThreadArgRetval::GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs) {
10106c3fb27SDimitry Andric   CheckLocked();
10206c3fb27SDimitry Andric   CHECK(ptrs);
10306c3fb27SDimitry Andric   data_.forEach([&](DenseMap<uptr, Data>::value_type& kv) -> bool {
10406c3fb27SDimitry Andric     ptrs->push_back((uptr)kv.second.args.arg_retval);
10506c3fb27SDimitry Andric     return true;
10606c3fb27SDimitry Andric   });
10706c3fb27SDimitry Andric }
10806c3fb27SDimitry Andric 
10906c3fb27SDimitry Andric }  // namespace __sanitizer
110