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