/* * Copyright 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include "fuzzer/FuzzedDataProvider.h" #include "utils/RefBase.h" #include "utils/StrongPointer.h" using android::RefBase; using android::sp; using android::wp; static constexpr int REFBASE_INITIAL_STRONG_VALUE = (1 << 28); static constexpr int REFBASE_MAX_COUNT = 0xfffff; static constexpr int MAX_OPERATIONS = 100; static constexpr int MAX_THREADS = 10; bool canDecrementStrong(RefBase* ref) { // There's an assert around decrementing the strong count too much that causes an artificial // crash This is just running BAD_STRONG from RefBase const int32_t count = ref->getStrongCount() - 1; return !(count == 0 || ((count) & (~(REFBASE_MAX_COUNT | REFBASE_INITIAL_STRONG_VALUE))) != 0); } bool canDecrementWeak(RefBase* ref) { const int32_t count = ref->getWeakRefs()->getWeakCount() - 1; return !((count) == 0 || ((count) & (~REFBASE_MAX_COUNT)) != 0); } struct RefBaseSubclass : public RefBase { RefBaseSubclass() {} virtual ~RefBaseSubclass() {} }; std::vector> operations = { [](RefBaseSubclass* ref) -> void { ref->getStrongCount(); }, [](RefBaseSubclass* ref) -> void { ref->printRefs(); }, [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->printRefs(); }, [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->getWeakCount(); }, [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->refBase(); }, [](RefBaseSubclass* ref) -> void { ref->incStrong(nullptr); }, [](RefBaseSubclass* ref) -> void { if (canDecrementStrong(ref)) { ref->decStrong(nullptr); } }, [](RefBaseSubclass* ref) -> void { ref->forceIncStrong(nullptr); }, [](RefBaseSubclass* ref) -> void { ref->createWeak(nullptr); }, [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->attemptIncStrong(nullptr); }, [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->attemptIncWeak(nullptr); }, [](RefBaseSubclass* ref) -> void { if (canDecrementWeak(ref)) { ref->getWeakRefs()->decWeak(nullptr); } }, [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->incWeak(nullptr); }, [](RefBaseSubclass* ref) -> void { ref->getWeakRefs()->printRefs(); }, }; void loop(RefBaseSubclass* loopRef, const std::vector& fuzzOps) { for (auto op : fuzzOps) { operations[op % operations.size()](loopRef); } } void spawnThreads(FuzzedDataProvider* dataProvider) { std::vector threads = std::vector(); // Get the number of threads to generate uint8_t count = dataProvider->ConsumeIntegralInRange(1, MAX_THREADS); // Generate threads for (uint8_t i = 0; i < count; i++) { RefBaseSubclass* threadRef = new RefBaseSubclass(); uint8_t opCount = dataProvider->ConsumeIntegralInRange(1, MAX_OPERATIONS); std::vector threadOperations = dataProvider->ConsumeBytes(opCount); std::thread tmp = std::thread(loop, threadRef, threadOperations); threads.push_back(move(tmp)); } for (auto& th : threads) { th.join(); } } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { FuzzedDataProvider dataProvider(data, size); spawnThreads(&dataProvider); return 0; }