mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-26 12:36:07 +00:00

Calling one of pthread join/detach interceptor on an already joined/detached thread causes asserts such as: AddressSanitizer: CHECK failed: sanitizer_thread_arg_retval.cpp:56 "((t)) != (0)" (0x0, 0x0) (tid=1236094) #0 0x555555634f8b in __asan::CheckUnwind() compiler-rt/lib/asan/asan_rtl.cpp:69:3 #1 0x55555564e06e in __sanitizer::CheckFailed(char const*, int, char const*, unsigned long long, unsigned long long) compiler-rt/lib/sanitizer_common/sanitizer_termination.cpp:86:24 #2 0x5555556491df in __sanitizer::ThreadArgRetval::BeforeJoin(unsigned long) const compiler-rt/lib/sanitizer_common/sanitizer_thread_arg_retval.cpp:56:3 #3 0x5555556198ed in Join<___interceptor_pthread_tryjoin_np(void*, void**)::<lambda()> > compiler-rt/lib/asan/../sanitizer_common/sanitizer_thread_arg_retval.h:74:26 #4 0x5555556198ed in pthread_tryjoin_np compiler-rt/lib/asan/asan_interceptors.cpp:311:29 The assert are replaced by error codes.
110 lines
2.9 KiB
C++
110 lines
2.9 KiB
C++
//===-- 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_++;
|
|
static_assert(sizeof(gen_) == sizeof(u32) && kInvalidGen == UINT32_MAX);
|
|
if (gen_ == kInvalidGen)
|
|
gen_ = 0;
|
|
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);
|
|
if (!t)
|
|
return;
|
|
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);
|
|
if (t && !t->second.detached) {
|
|
return t->second.gen;
|
|
}
|
|
if (!common_flags()->detect_invalid_join)
|
|
return kInvalidGen;
|
|
const char* reason = "unknown";
|
|
if (!t) {
|
|
reason = "already joined";
|
|
} else if (t->second.detached) {
|
|
reason = "detached";
|
|
}
|
|
Report("ERROR: %s: Joining %s thread, aborting.\n", SanitizerToolName,
|
|
reason);
|
|
Die();
|
|
}
|
|
|
|
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, or we had an invalid
|
|
// join.
|
|
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
|