xref: /llvm-project/compiler-rt/lib/sanitizer_common/tests/sanitizer_thread_arg_retval_test.cpp (revision c45ee7c0fba8daa2b5b6b201faa99d02c01cce8b)
1 //===-- sanitizer_thread_registry_test.cpp --------------------------------===//
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 a part of shared sanitizer runtime.
10 //
11 //===----------------------------------------------------------------------===//
12 #include "sanitizer_common/sanitizer_thread_arg_retval.h"
13 
14 #include "gtest/gtest.h"
15 #include "sanitizer_mutex.h"
16 
17 namespace __sanitizer {
18 
19 static int t;
20 static void* arg = &t;
__anon555fb23d0102(void*) 21 static void* (*routine)(void*) = [](void*) { return arg; };
22 static void* retval = (&t) + 1;
23 
TEST(ThreadArgRetvalTest,CreateFail)24 TEST(ThreadArgRetvalTest, CreateFail) {
25   ThreadArgRetval td;
26   td.Create(false, {routine, arg}, []() { return 0; });
27   EXPECT_EQ(0u, td.size());
28 }
29 
TEST(ThreadArgRetvalTest,CreateRunJoin)30 TEST(ThreadArgRetvalTest, CreateRunJoin) {
31   ThreadArgRetval td;
32   td.Create(false, {routine, arg}, []() { return 1; });
33   EXPECT_EQ(1u, td.size());
34 
35   EXPECT_EQ(arg, td.GetArgs(1).arg_retval);
36   EXPECT_EQ(routine, td.GetArgs(1).routine);
37   EXPECT_EQ(1u, td.size());
38 
39   td.Finish(1, retval);
40   EXPECT_EQ(1u, td.size());
41 
42   td.Join(1, []() { return false; });
43   EXPECT_EQ(1u, td.size());
44 
45   td.Join(1, []() { return true; });
46   EXPECT_EQ(0u, td.size());
47 }
48 
TEST(ThreadArgRetvalTest,CreateJoinRun)49 TEST(ThreadArgRetvalTest, CreateJoinRun) {
50   ThreadArgRetval td;
51   td.Create(false, {routine, arg}, []() { return 1; });
52   EXPECT_EQ(1u, td.size());
53 
54   td.Join(1, []() { return false; });
55   EXPECT_EQ(1u, td.size());
56 
57   td.Join(1, [&]() {
58     // Expected to happen on another thread.
59     EXPECT_EQ(1u, td.size());
60 
61     EXPECT_EQ(arg, td.GetArgs(1).arg_retval);
62     EXPECT_EQ(routine, td.GetArgs(1).routine);
63     EXPECT_EQ(1u, td.size());
64 
65     td.Finish(1, retval);
66     EXPECT_EQ(1u, td.size());
67     return true;
68   });
69   EXPECT_EQ(0u, td.size());
70 }
71 
TEST(ThreadArgRetvalTest,CreateRunDetach)72 TEST(ThreadArgRetvalTest, CreateRunDetach) {
73   ThreadArgRetval td;
74   td.Create(false, {routine, arg}, []() { return 1; });
75   EXPECT_EQ(1u, td.size());
76 
77   EXPECT_EQ(arg, td.GetArgs(1).arg_retval);
78   EXPECT_EQ(routine, td.GetArgs(1).routine);
79   EXPECT_EQ(1u, td.size());
80 
81   td.Finish(1, retval);
82   EXPECT_EQ(1u, td.size());
83 
84   td.Detach(1, []() { return false; });
85   EXPECT_EQ(1u, td.size());
86 
87   td.Detach(1, []() { return true; });
88   EXPECT_EQ(0u, td.size());
89 }
90 
TEST(ThreadArgRetvalTest,CreateDetachRun)91 TEST(ThreadArgRetvalTest, CreateDetachRun) {
92   ThreadArgRetval td;
93   td.Create(false, {routine, arg}, []() { return 1; });
94   EXPECT_EQ(1u, td.size());
95 
96   td.Detach(1, []() { return true; });
97   EXPECT_EQ(1u, td.size());
98 
99   EXPECT_EQ(arg, td.GetArgs(1).arg_retval);
100   EXPECT_EQ(routine, td.GetArgs(1).routine);
101   EXPECT_EQ(1u, td.size());
102 
103   td.Finish(1, retval);
104   EXPECT_EQ(0u, td.size());
105 }
106 
TEST(ThreadArgRetvalTest,CreateRunJoinReuse)107 TEST(ThreadArgRetvalTest, CreateRunJoinReuse) {
108   ThreadArgRetval td;
109   td.Create(false, {routine, arg}, []() { return 1; });
110   EXPECT_EQ(1u, td.size());
111 
112   td.Finish(1, retval);
113   EXPECT_EQ(1u, td.size());
114 
115   td.Join(1, [&]() {
116     // Reuse thread id.
117     td.Create(false, {routine, arg}, []() { return 1; });
118     EXPECT_EQ(1u, td.size());
119     return true;
120   });
121   // Even if JoinFn succeeded, we can't erase mismatching thread.
122   EXPECT_EQ(1u, td.size());
123 
124   // Now we can join another one.
125   td.Join(1, []() { return true; });
126   EXPECT_EQ(0u, td.size());
127 }
128 
TEST(ThreadArgRetvalTest,GetAllPtrsLocked)129 TEST(ThreadArgRetvalTest, GetAllPtrsLocked) {
130   ThreadArgRetval td;
131   td.Create(false, {routine, arg}, []() { return 1; });
132   {
133     GenericScopedLock<ThreadArgRetval> lock(&td);
134     InternalMmapVector<uptr> ptrs;
135     td.GetAllPtrsLocked(&ptrs);
136     EXPECT_EQ(1u, ptrs.size());
137     EXPECT_EQ((uptr)arg, ptrs[0]);
138   }
139 
140   td.Finish(1, retval);
141   {
142     GenericScopedLock<ThreadArgRetval> lock(&td);
143     InternalMmapVector<uptr> ptrs;
144     td.GetAllPtrsLocked(&ptrs);
145     EXPECT_EQ(1u, ptrs.size());
146     EXPECT_EQ((uptr)retval, ptrs[0]);
147   }
148 
149   td.Join(1, []() { return true; });
150   {
151     GenericScopedLock<ThreadArgRetval> lock(&td);
152     InternalMmapVector<uptr> ptrs;
153     td.GetAllPtrsLocked(&ptrs);
154     EXPECT_TRUE(ptrs.empty());
155   }
156 }
157 
158 }  // namespace __sanitizer
159