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-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#ifndef SANITIZER_THREAD_ARG_RETVAL_H
15#define SANITIZER_THREAD_ARG_RETVAL_H
16
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 leak
25// checking. However it can be used to pass those pointer into wrappers used by
26// interceptors. The difference from ThreadRegistry/ThreadList is that this
27// class keeps data up to the detach or join, as exited thread still can be
28// joined to retrive retval. ThreadRegistry/ThreadList can discard exited
29// 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, to
41 // 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's
45 // 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 be
55 // 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 thread
72 // between fn() and AfterJoin() calls. Locking JoinFn, like in
73 // 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 forks
88 // anyway. We likely should lock/unlock the object to avoid deadlocks, and
89 // erase all but the current threads, so we can detect leaked arg or retval in
90 // child process.
91
92 // FIXME: Add cancelation support. Now if a thread was canceled, the class
93 // 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 __sanitizer
116
117#endif // SANITIZER_THREAD_ARG_RETVAL_H
118