master
  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
 18namespace __sanitizer {
 19
 20void 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
 33ThreadArgRetval::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
 42void 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
 56u32 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
 75void 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
 87void 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
100void 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