summaryrefslogtreecommitdiff
path: root/compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.cpp
blob: 85362e8a97218403021b1edd4faab79fc738908c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
//===-- sanitizer_thread_arg_retval.cpp -------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file is shared between sanitizer tools.
//
// Tracks thread arguments and return value for leak checking.
//===----------------------------------------------------------------------===//

#include "sanitizer_thread_arg_retval.h"

#include "sanitizer_placement_new.h"

namespace __sanitizer {

void ThreadArgRetval::CreateLocked(uptr thread, bool detached,
                                   const Args& args) {
  CheckLocked();
  Data& t = data_[thread];
  t = {};
  t.gen = gen_++;
  t.detached = detached;
  t.args = args;
}

ThreadArgRetval::Args ThreadArgRetval::GetArgs(uptr thread) const {
  __sanitizer::Lock lock(&mtx_);
  auto t = data_.find(thread);
  CHECK(t);
  if (t->second.done)
    return {};
  return t->second.args;
}

void ThreadArgRetval::Finish(uptr thread, void* retval) {
  __sanitizer::Lock lock(&mtx_);
  auto t = data_.find(thread);
  CHECK(t);
  if (t->second.detached) {
    // Retval of detached thread connot be retrieved.
    data_.erase(t);
    return;
  }
  t->second.done = true;
  t->second.args.arg_retval = retval;
}

u32 ThreadArgRetval::BeforeJoin(uptr thread) const {
  __sanitizer::Lock lock(&mtx_);
  auto t = data_.find(thread);
  CHECK(t);
  CHECK(!t->second.detached);
  return t->second.gen;
}

void ThreadArgRetval::AfterJoin(uptr thread, u32 gen) {
  __sanitizer::Lock lock(&mtx_);
  auto t = data_.find(thread);
  if (!t || gen != t->second.gen) {
    // Thread was reused and erased by any other event.
    return;
  }
  CHECK(!t->second.detached);
  data_.erase(t);
}

void ThreadArgRetval::DetachLocked(uptr thread) {
  CheckLocked();
  auto t = data_.find(thread);
  CHECK(t);
  CHECK(!t->second.detached);
  if (t->second.done) {
    // We can't retrive retval after detached thread finished.
    data_.erase(t);
    return;
  }
  t->second.detached = true;
}

void ThreadArgRetval::GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs) {
  CheckLocked();
  CHECK(ptrs);
  data_.forEach([&](DenseMap<uptr, Data>::value_type& kv) -> bool {
    ptrs->push_back((uptr)kv.second.args.arg_retval);
    return true;
  });
}

}  // namespace __sanitizer