118 lines · c
1//===-- sanitizer_thread_arg_retval.h ---------------------------*- 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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is shared between sanitizer tools.10//11// Tracks thread arguments and return value for leak checking.12//===----------------------------------------------------------------------===//13 14#ifndef SANITIZER_THREAD_ARG_RETVAL_H15#define SANITIZER_THREAD_ARG_RETVAL_H16 17#include "sanitizer_common.h"18#include "sanitizer_dense_map.h"19#include "sanitizer_list.h"20#include "sanitizer_mutex.h"21 22namespace __sanitizer {23 24// Primary goal of the class is to keep alive arg and retval pointer for leak25// checking. However it can be used to pass those pointer into wrappers used by26// interceptors. The difference from ThreadRegistry/ThreadList is that this27// class keeps data up to the detach or join, as exited thread still can be28// joined to retrive retval. ThreadRegistry/ThreadList can discard exited29// threads immediately.30class SANITIZER_MUTEX ThreadArgRetval {31 public:32 struct Args {33 void* (*routine)(void*);34 void* arg_retval; // Either arg or retval.35 };36 void Lock() SANITIZER_ACQUIRE() { mtx_.Lock(); }37 void CheckLocked() const SANITIZER_CHECK_LOCKED() { mtx_.CheckLocked(); }38 void Unlock() SANITIZER_RELEASE() { mtx_.Unlock(); }39 40 // Wraps pthread_create or similar. We need to keep object locked, to41 // prevent child thread from proceeding without thread handle.42 template <typename CreateFn /* returns thread id on success, or 0 */>43 void Create(bool detached, const Args& args, const CreateFn& fn) {44 // No need to track detached threads with no args, but we will to do as it's45 // not expensive and less edge-cases.46 __sanitizer::Lock lock(&mtx_);47 if (uptr thread = fn())48 CreateLocked(thread, detached, args);49 }50 51 // Returns thread arg and routine.52 Args GetArgs(uptr thread) const;53 54 // Mark thread as done and stores retval or remove if detached. Should be55 // called by the thread.56 void Finish(uptr thread, void* retval);57 58 // Mark thread as detached or remove if done.59 template <typename DetachFn /* returns true on success */>60 void Detach(uptr thread, const DetachFn& fn) {61 // Lock to prevent re-use of the thread between fn() and DetachLocked()62 // calls.63 __sanitizer::Lock lock(&mtx_);64 if (fn())65 DetachLocked(thread);66 }67 68 // Joins the thread.69 template <typename JoinFn /* returns true on success */>70 void Join(uptr thread, const JoinFn& fn) {71 // Remember internal id of the thread to prevent re-use of the thread72 // between fn() and AfterJoin() calls. Locking JoinFn, like in73 // Detach(), implementation can cause deadlock.74 auto gen = BeforeJoin(thread);75 if (fn())76 AfterJoin(thread, gen);77 }78 79 // Returns all arg and retval which are considered alive.80 void GetAllPtrsLocked(InternalMmapVector<uptr>* ptrs);81 82 uptr size() const {83 __sanitizer::Lock lock(&mtx_);84 return data_.size();85 }86 87 // FIXME: Add fork support. Expected users of the class are sloppy with forks88 // anyway. We likely should lock/unlock the object to avoid deadlocks, and89 // erase all but the current threads, so we can detect leaked arg or retval in90 // child process.91 92 // FIXME: Add cancelation support. Now if a thread was canceled, the class93 // will keep pointers alive forever, missing leaks caused by cancelation.94 95 private:96 static const u32 kInvalidGen = UINT32_MAX;97 struct Data {98 Args args;99 u32 gen; // Avoid collision if thread id re-used.100 bool detached;101 bool done;102 };103 104 void CreateLocked(uptr thread, bool detached, const Args& args);105 u32 BeforeJoin(uptr thread) const;106 void AfterJoin(uptr thread, u32 gen);107 void DetachLocked(uptr thread);108 109 mutable Mutex mtx_;110 111 DenseMap<uptr, Data> data_;112 u32 gen_ = 0;113};114 115} // namespace __sanitizer116 117#endif // SANITIZER_THREAD_ARG_RETVAL_H118