//===-- weak_avl_fuzz.cpp -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// Fuzzing test for llvm-libc weak AVL implementations. /// //===----------------------------------------------------------------------===// #include "hdr/types/ENTRY.h" #include "src/__support/CPP/bit.h" #include "src/__support/CPP/optional.h" #include "src/__support/macros/config.h" #include "src/__support/weak_avl.h" namespace LIBC_NAMESPACE_DECL { // A sequence of actions: // - Erase: a single byte valued (5, 6 mod 7) followed by an int // - Find: a single byte valued (4 mod 7) followed by an int // - FindOrInsert: a single byte valued (0,1,2,3 mod 7) followed by an int extern "C" size_t LLVMFuzzerMutate(uint8_t *data, size_t size, size_t max_size); extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *data, size_t size, size_t max_size, unsigned int seed) { size = LLVMFuzzerMutate(data, size, max_size); return size / (1 + sizeof(int)) * (1 + sizeof(int)); } class AVLTree { using Node = WeakAVLNode; Node *root = nullptr; bool reversed = false; static int compare(int a, int b) { return (a > b) - (a < b); } static int reverse_compare(int a, int b) { return (b > a) - (b < a); } public: AVLTree(bool reversed = false) : reversed(reversed) {} bool find(int key) { return Node::find(root, key, reversed ? reverse_compare : compare) .has_value(); } bool find_or_insert(int key) { return Node::find_or_insert(root, key, reversed ? reverse_compare : compare) .has_value(); } bool erase(int key) { if (cpp::optional node = Node::find(root, key, reversed ? reverse_compare : compare)) { Node::erase(root, node.value()); return true; } return false; } ~AVLTree() { Node::destroy(root); } }; extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { AVLTree tree1; AVLTree tree2(true); for (size_t i = 0; i + (1 + sizeof(int)) <= size; i += 1 + sizeof(int)) { uint8_t action = data[i]; int key; __builtin_memcpy(&key, data + i + 1, sizeof(int)); if (action % 7 == 4) { // Find bool res1 = tree1.find(key); bool res2 = tree2.find(key); if (res1 != res2) __builtin_trap(); } else if (action % 7 == 5 || action % 7 == 6) { // Erase bool res1 = tree1.erase(key); bool res2 = tree2.erase(key); if (res1 != res2) __builtin_trap(); if (tree1.find(key)) __builtin_trap(); if (tree2.find(key)) __builtin_trap(); } else { // FindOrInsert bool res1 = tree1.find_or_insert(key); bool res2 = tree2.find_or_insert(key); if (res1 != res2) __builtin_trap(); if (!tree1.find(key)) __builtin_trap(); if (!tree2.find(key)) __builtin_trap(); } } return 0; } } // namespace LIBC_NAMESPACE_DECL