1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "refbase_fuzzer.h"
17
18 #include <thread>
19 #include <vector>
20
21 #include "fuzz_log.h"
22 #include "fuzzer/FuzzedDataProvider.h"
23 #include "refbase.h"
24 #include "rwlock.h"
25
26 using namespace std;
27
28 namespace OHOS {
29 const int MAX_THREADS = 10;
30 const int MAX_OPS = 200;
31 const int SLEEP_NANO_SECONDS = 10;
32
GetThreadId()33 uint32_t GetThreadId()
34 {
35 std::thread::id tid = this_thread::get_id();
36 return *reinterpret_cast<uint32_t*>(&tid);
37 }
38
39 struct TestRefBase : public RefBase {
40 public:
TestRefBaseOHOS::TestRefBase41 TestRefBase(bool* deleted, Utils::RWLock& rwLock) : deleted_(deleted), rwLock_(rwLock)
42 {
43 rwLock_.LockWrite();
44 *deleted_ = false;
45 rwLock_.UnLockWrite();
46 ExtendObjectLifetime();
47 }
48
~TestRefBaseOHOS::TestRefBase49 virtual ~TestRefBase()
50 {
51 rwLock_.LockWrite();
52 *deleted_ = true;
53 rwLock_.UnLockWrite();
54 }
55
56 void OnLastStrongRef(const void* objectId) override;
57 void OnFirstStrongRef(const void* objectId) override;
58
59 private:
60 bool* deleted_;
61 Utils::RWLock& rwLock_;
62 };
63
OnLastStrongRef(const void * objectId)64 void TestRefBase::OnLastStrongRef(const void* objectId)
65 {
66 std::this_thread::sleep_for(std::chrono::nanoseconds(SLEEP_NANO_SECONDS));
67 }
68
OnFirstStrongRef(const void * objectId)69 void TestRefBase::OnFirstStrongRef(const void* objectId)
70 {
71 std::this_thread::sleep_for(std::chrono::nanoseconds(SLEEP_NANO_SECONDS));
72 }
73
74 struct SingleThreadRefCounts {
75 size_t strongCount = 0;
76 size_t weakCount = 0;
77 bool weakRefCounterExists = false;
78 size_t weakRefCount = 0;
79 };
80
81 TestRefBase* g_ref;
82 bool g_refModified = false;
83 bool g_refDeleted = false;
84 Utils::RWLock g_deletedLock;
85 Utils::RWLock g_strongLock;
86 Utils::RWLock g_attemptLock;
87
88 const std::vector<std::function<void(SingleThreadRefCounts*, WeakRefCounter*&)>> decOperations = {
__anone27d57a10102() 89 [](SingleThreadRefCounts* refState, WeakRefCounter*&) {
90 if (refState->strongCount > 0) {
91 refState->strongCount--;
92 bool shouldLock = refState->strongCount == 0 && refState->weakCount == 0 && refState->weakRefCount == 0;
93 if (shouldLock) {
94 g_strongLock.LockWrite();
95 }
96 FUZZ_LOGI("thread = %{public}u, DecStrongRef, refState->strongCount = %{public}zu", GetThreadId(),
97 refState->strongCount);
98 g_ref->DecStrongRef(nullptr);
99 if (shouldLock) {
100 g_strongLock.UnLockWrite();
101 }
102 g_refModified = true;
103 }
104 },
105
__anone27d57a10202() 106 [](SingleThreadRefCounts* refState, WeakRefCounter*& weakRef) {
107 if (refState->weakRefCount > 0) {
108 refState->weakRefCount--;
109 refState->weakRefCounterExists = refState->weakRefCount > 0;
110 bool shouldLock = refState->strongCount == 0 && refState->weakCount == 0 && refState->weakRefCount == 0;
111 if (shouldLock) {
112 g_strongLock.LockWrite();
113 }
114 FUZZ_LOGI("thread = %{public}u, weakRef->DecWeakRefCount, refState->weakRefCount = %{public}zu",
115 GetThreadId(), refState->weakRefCount);
116 weakRef->DecWeakRefCount(nullptr);
117 if (shouldLock) {
118 g_strongLock.UnLockWrite();
119 }
120 g_refModified = true;
121 }
122 },
123
__anone27d57a10302() 124 [](SingleThreadRefCounts* refState, WeakRefCounter*&) {
125 if (refState->weakCount > 0) {
126 refState->weakCount--;
127 bool shouldLock = refState->strongCount == 0 && refState->weakCount == 0 && refState->weakRefCount == 0;
128 if (shouldLock) {
129 g_strongLock.LockWrite();
130 }
131 FUZZ_LOGI("thread = %{public}u, DecWeakRef, refState->weakCount = %{public}zu", GetThreadId(),
132 refState->weakCount);
133 g_ref->DecWeakRef(nullptr);
134 if (shouldLock) {
135 g_strongLock.UnLockWrite();
136 }
137 g_refModified = true;
138 }
139 },
140 };
141
142 const std::vector<std::function<void(SingleThreadRefCounts*, WeakRefCounter*&)>> readOrIncOperations = {
__anone27d57a10402() 143 [](SingleThreadRefCounts*, WeakRefCounter*&) {
144 FUZZ_LOGI("thread = %{public}u, GetSptrRefCount", GetThreadId());
145 g_ref->GetSptrRefCount();
146 },
147
__anone27d57a10502() 148 [](SingleThreadRefCounts*, WeakRefCounter*&) {
149 FUZZ_LOGI("thread = %{public}u, GetRefCounter", GetThreadId());
150 RefCounter* refCounter = g_ref->GetRefCounter();
151 if (refCounter != nullptr) {
152 refCounter->GetRefCount();
153 }
154 },
155
__anone27d57a10602() 156 [](SingleThreadRefCounts*, WeakRefCounter*&) {
157 FUZZ_LOGI("thread = %{public}u, GetWptrRefCount", GetThreadId());
158 g_ref->GetWptrRefCount();
159 },
160
__anone27d57a10702() 161 [](SingleThreadRefCounts*, WeakRefCounter*&) {
162 FUZZ_LOGI("thread = %{public}u, IsAttemptAcquireSet", GetThreadId());
163 g_ref->IsAttemptAcquireSet();
164 },
165
__anone27d57a10802() 166 [](SingleThreadRefCounts*, WeakRefCounter*&) {
167 FUZZ_LOGI("thread = %{public}u, IsExtendLifeTimeSet", GetThreadId());
168 g_ref->IsExtendLifeTimeSet();
169 },
170
__anone27d57a10902() 171 [](SingleThreadRefCounts* refState, WeakRefCounter*& weakRef) {
172 if (refState->weakRefCounterExists) {
173 FUZZ_LOGI("thread = %{public}u, weakRef->GetWeakRefCount", GetThreadId());
174 weakRef->GetWeakRefCount();
175 }
176 },
177
__anone27d57a10a02() 178 [](SingleThreadRefCounts* refState, WeakRefCounter*&) {
179 g_attemptLock.LockRead();
180 FUZZ_LOGI("thread = %{public}u, IncStrongRef", GetThreadId());
181 g_ref->IncStrongRef(nullptr);
182 refState->strongCount++;
183 g_refModified = true;
184 g_attemptLock.UnLockRead();
185 },
186
__anone27d57a10b02() 187 [](SingleThreadRefCounts* refState, WeakRefCounter*& weakRef) {
188 if (!refState->weakRefCounterExists) {
189 FUZZ_LOGI("thread = %{public}u, CreateWeakRef", GetThreadId());
190 weakRef = g_ref->CreateWeakRef(nullptr);
191 refState->weakRefCounterExists = true;
192 // Only CreateWeakRef then release, will not delete RefBase, so g_refModified will not change.
193 }
194 },
195
__anone27d57a10c02() 196 [](SingleThreadRefCounts* refState, WeakRefCounter*& weakRef) {
197 if (refState->weakRefCounterExists) {
198 FUZZ_LOGI("thread = %{public}u, weakRef->IncWeakRefCount", GetThreadId());
199 weakRef->IncWeakRefCount(nullptr);
200 refState->weakRefCount++;
201 g_refModified = true;
202 }
203 },
204
__anone27d57a10d02() 205 [](SingleThreadRefCounts* refState, WeakRefCounter*& weakRef) {
206 if (refState->weakRefCounterExists) {
207 g_attemptLock.LockWrite();
208 FUZZ_LOGI("thread = %{public}u, weakRef->AttemptIncStrongRef", GetThreadId());
209 weakRef->AttemptIncStrongRef(nullptr);
210 refState->strongCount++;
211 g_refModified = true;
212 g_attemptLock.UnLockWrite();
213 }
214 },
215
__anone27d57a10e02() 216 [](SingleThreadRefCounts* refState, WeakRefCounter*&) {
217 FUZZ_LOGI("thread = %{public}u, IncWeakRef", GetThreadId());
218 g_ref->IncWeakRef(nullptr);
219 refState->weakCount++;
220 g_refModified = true;
221 },
222
__anone27d57a10f02() 223 [](SingleThreadRefCounts* refState, WeakRefCounter*&) {
224 g_attemptLock.LockWrite();
225 FUZZ_LOGI("thread = %{public}u, AttemptAcquire", GetThreadId());
226 g_ref->AttemptAcquire(nullptr);
227 g_ref->IncStrongRef(nullptr);
228 refState->strongCount++;
229 g_refModified = true;
230 g_attemptLock.UnLockWrite();
231 },
232
__anone27d57a11002() 233 [](SingleThreadRefCounts* refState, WeakRefCounter*&) {
234 g_attemptLock.LockWrite();
235 FUZZ_LOGI("thread = %{public}u, AttemptIncStrongRef", GetThreadId());
236 g_ref->AttemptIncStrongRef(nullptr);
237 refState->strongCount++;
238 g_refModified = true;
239 g_attemptLock.UnLockWrite();
240 },
241
__anone27d57a11102() 242 [](SingleThreadRefCounts* refState, WeakRefCounter*&) {
243 g_attemptLock.LockWrite();
244 FUZZ_LOGI("thread = %{public}u, AttemptIncStrong", GetThreadId());
245 g_ref->AttemptIncStrong(nullptr);
246 g_ref->IncStrongRef(nullptr);
247 refState->strongCount++;
248 g_refModified = true;
249 g_attemptLock.UnLockWrite();
250 },
251 };
252
253 // Clean up WeakRefCounter
CleanUpWeakRefCounter(SingleThreadRefCounts & state,WeakRefCounter * newWeakRef)254 void CleanUpWeakRefCounter(SingleThreadRefCounts& state, WeakRefCounter* newWeakRef)
255 {
256 if (state.weakRefCounterExists) {
257 FUZZ_LOGI("thread = %{public}u, delete newWeakRef", GetThreadId());
258 delete newWeakRef;
259 } else if (state.weakRefCount > 0) {
260 for (; state.weakRefCount > 0; --state.weakRefCount) {
261 bool shouldLock = state.strongCount == 0 && state.weakCount == 0 && state.weakRefCount == 0;
262 if (shouldLock) {
263 g_strongLock.LockWrite();
264 }
265 FUZZ_LOGI("thread = %{public}u, clean up DecWeakRefCount, refState->weakRefCount = %{public}zu",
266 GetThreadId(), state.weakRefCount);
267 newWeakRef->DecWeakRefCount(nullptr);
268 if (shouldLock) {
269 g_strongLock.UnLockWrite();
270 }
271 }
272 }
273 }
274
275 // Clean up any weak references
CleanUpWeakCounter(SingleThreadRefCounts & state)276 void CleanUpWeakCounter(SingleThreadRefCounts& state)
277 {
278 for (; state.weakCount > 0; state.weakCount--) {
279 bool shouldLock = state.strongCount == 0 && state.weakCount == 1;
280 if (shouldLock) {
281 g_strongLock.LockWrite();
282 }
283 FUZZ_LOGI("thread = %{public}u, clean up DecWeakRef, refState->weakCount = %{public}zu", GetThreadId(),
284 state.weakCount - 1);
285 g_ref->DecWeakRef(nullptr);
286 if (shouldLock) {
287 g_strongLock.UnLockWrite();
288 }
289 }
290 }
291
292 // Clean up any strong references
CleanUpStrongCounter(SingleThreadRefCounts & state)293 void CleanUpStrongCounter(SingleThreadRefCounts& state)
294 {
295 for (; state.strongCount > 0; state.strongCount--) {
296 bool shouldLock = state.strongCount == 1;
297 if (shouldLock) {
298 g_strongLock.LockWrite();
299 }
300 FUZZ_LOGI("thread = %{public}u, clean up DecStrongRef, refState->strongCount = %{public}zu", GetThreadId(),
301 state.strongCount - 1);
302 g_ref->DecStrongRef(nullptr);
303 if (shouldLock) {
304 g_strongLock.UnLockWrite();
305 }
306 }
307 }
308
TestLoop(const std::vector<uint8_t> & fuzzOps)309 void TestLoop(const std::vector<uint8_t>& fuzzOps)
310 {
311 SingleThreadRefCounts state;
312 uint8_t lockedOpSize = readOrIncOperations.size();
313 uint8_t totalOperationTypes = lockedOpSize + decOperations.size();
314 WeakRefCounter* newWeakRef = nullptr;
315
316 for (auto op : fuzzOps) {
317 auto opVal = op % totalOperationTypes;
318 if (opVal >= lockedOpSize) {
319 decOperations[opVal % lockedOpSize](&state, newWeakRef);
320 } else {
321 bool shouldLock = state.strongCount == 0 && state.weakCount == 0 && state.weakRefCount == 0;
322 if (shouldLock) {
323 g_strongLock.LockRead();
324 if (g_refDeleted) {
325 if (state.weakRefCounterExists) {
326 FUZZ_LOGI("thread = %{public}u, delete newWeakRef", GetThreadId());
327 delete newWeakRef;
328 }
329 FUZZ_LOGI("thread = %{public}u return", GetThreadId());
330 g_strongLock.UnLockRead();
331 return;
332 }
333 }
334 readOrIncOperations[opVal](&state, newWeakRef);
335 if (shouldLock) {
336 g_strongLock.UnLockRead();
337 }
338 }
339 }
340
341 CleanUpWeakRefCounter(state, newWeakRef);
342 CleanUpWeakCounter(state);
343 CleanUpStrongCounter(state);
344 }
345
RefbaseTestFunc(const uint8_t * data,size_t size,FuzzedDataProvider * dataProvider)346 void RefbaseTestFunc(const uint8_t* data, size_t size, FuzzedDataProvider* dataProvider)
347 {
348 FUZZ_LOGI("RefbaseTestFunc start");
349 g_ref = new TestRefBase(&g_refDeleted, g_deletedLock);
350 g_refModified = false;
351 uint8_t threadNum = 1;
352 vector<thread> threads = vector<thread>();
353 threadNum = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_THREADS);
354
355 for (uint8_t i = 0; i < threadNum; i++) {
356 uint8_t opsSize = 1;
357 opsSize = dataProvider->ConsumeIntegralInRange<uint8_t>(1, MAX_OPS);
358 vector<uint8_t> ops = dataProvider->ConsumeBytes<uint8_t>(opsSize);
359 thread threadTmp = thread(TestLoop, ops);
360 threads.push_back(move(threadTmp));
361 }
362
363 for (thread& th : threads) {
364 th.join();
365 }
366
367 if (!g_refModified && !g_refDeleted) {
368 delete g_ref;
369 g_ref = nullptr;
370 }
371 FUZZ_LOGI("RefbaseTestFunc end");
372 }
373
374 } // namespace OHOS
375
376 /* Fuzzer entry point */
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)377 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
378 {
379 FuzzedDataProvider dataProvider(data, size);
380 OHOS::RefbaseTestFunc(data, size, &dataProvider);
381 return 0;
382 }
383