blob: a5d3efe6e5dacce659210fa1d6d9a8df4535974d [file] [log] [blame] [edit]
//===-- 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<int>;
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 =
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