[libc-commits] [libc] [libc] add hashtable fuzzing (PR #87949)
Schrodinger ZHU Yifan via libc-commits
libc-commits at lists.llvm.org
Fri Apr 19 14:57:06 PDT 2024
https://github.com/SchrodingerZhu updated https://github.com/llvm/llvm-project/pull/87949
>From b4d7cbc29a448ff490c43440f0ef4b351657782c Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Sun, 7 Apr 2024 18:26:16 -0400
Subject: [PATCH 1/5] [libc] add hashtable fuzzing
---
libc/fuzzing/__support/CMakeLists.txt | 9 ++
libc/fuzzing/__support/hashtable_fuzz.cpp | 157 ++++++++++++++++++++++
2 files changed, 166 insertions(+)
create mode 100644 libc/fuzzing/__support/hashtable_fuzz.cpp
diff --git a/libc/fuzzing/__support/CMakeLists.txt b/libc/fuzzing/__support/CMakeLists.txt
index d4f6db71fdd849..b5d2b488447fc5 100644
--- a/libc/fuzzing/__support/CMakeLists.txt
+++ b/libc/fuzzing/__support/CMakeLists.txt
@@ -5,3 +5,12 @@ add_libc_fuzzer(
DEPENDS
libc.src.__support.big_int
)
+
+add_libc_fuzzer(
+ hashtable_fuzz
+ SRCS
+ hashtable_fuzz.cpp
+ DEPENDS
+ libc.src.__support.HashTable.table
+ libc.src.string.memcpy
+)
diff --git a/libc/fuzzing/__support/hashtable_fuzz.cpp b/libc/fuzzing/__support/hashtable_fuzz.cpp
new file mode 100644
index 00000000000000..4b862b03b9d309
--- /dev/null
+++ b/libc/fuzzing/__support/hashtable_fuzz.cpp
@@ -0,0 +1,157 @@
+#include "src/__support/CPP/new.h"
+#include "src/__support/CPP/optional.h"
+#include "src/__support/HashTable/table.h"
+#include "src/string/memcpy.h"
+#include <search.h>
+#include <stdint.h>
+namespace LIBC_NAMESPACE {
+
+enum class Action { Find, Insert, CrossCheck };
+static uint8_t *global_buffer = nullptr;
+static size_t remaining = 0;
+
+static cpp::optional<uint8_t> next_u8() {
+ if (remaining == 0)
+ return cpp::nullopt;
+ uint8_t result = *global_buffer;
+ global_buffer++;
+ remaining--;
+ return result;
+}
+
+static cpp::optional<uint64_t> next_uint64() {
+ uint64_t result;
+ if (remaining < sizeof(result))
+ return cpp::nullopt;
+ memcpy(&result, global_buffer, sizeof(result));
+ global_buffer += sizeof(result);
+ remaining -= sizeof(result);
+ return result;
+}
+
+static cpp::optional<Action> next_action() {
+ if (cpp::optional<uint8_t> action = next_u8()) {
+ switch (*action % 3) {
+ case 0:
+ return Action::Find;
+ case 1:
+ return Action::Insert;
+ case 2:
+ return Action::CrossCheck;
+ }
+ }
+ return cpp::nullopt;
+}
+
+static cpp::optional<char *> next_cstr() {
+ char *result = reinterpret_cast<char *>(global_buffer);
+ if (cpp::optional<uint64_t> len = next_uint64()) {
+ uint64_t length;
+ for (length = 0; length < *len % 128; length++) {
+ if (length >= remaining)
+ return cpp::nullopt;
+ if (*global_buffer == '\0')
+ break;
+ }
+ if (length >= remaining)
+ return cpp::nullopt;
+ global_buffer[length] = '\0';
+ global_buffer += length + 1;
+ remaining -= length + 1;
+ return result;
+ }
+ return cpp::nullopt;
+}
+
+#define GET_VAL(op) \
+ __extension__({ \
+ auto val = op(); \
+ if (!val) \
+ return 0; \
+ *val; \
+ })
+
+template <typename Fn> struct CleanUpHook {
+ cpp::optional<Fn> fn;
+ ~CleanUpHook() {
+ if (fn)
+ (*fn)();
+ }
+ CleanUpHook(Fn fn) : fn(cpp::move(fn)) {}
+ CleanUpHook(const CleanUpHook &) = delete;
+ CleanUpHook(CleanUpHook &&other) : fn(cpp::move(other.fn)) {
+ other.fn = cpp::nullopt;
+ }
+};
+
+#define register_cleanup(ID, ...) \
+ auto cleanup_hook##ID = __extension__({ \
+ auto a = __VA_ARGS__; \
+ CleanUpHook<decltype(a)>{a}; \
+ });
+
+static void trap_with_message(const char *msg) { __builtin_trap(); }
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ AllocChecker ac;
+ global_buffer = static_cast<uint8_t *>(::operator new(size, ac));
+ register_cleanup(0, [global_buffer = global_buffer, size] {
+ ::operator delete(global_buffer, size);
+ });
+ if (!ac)
+ return 0;
+ memcpy(global_buffer, data, size);
+
+ remaining = size;
+ uint64_t size_a = GET_VAL(next_uint64) % 256;
+ uint64_t size_b = GET_VAL(next_uint64) % 256;
+ uint64_t rand_a = GET_VAL(next_uint64);
+ uint64_t rand_b = GET_VAL(next_uint64);
+ internal::HashTable *table_a = internal::HashTable::allocate(size_a, rand_a);
+ register_cleanup(1, [&table_a] { internal::HashTable::deallocate(table_a); });
+ internal::HashTable *table_b = internal::HashTable::allocate(size_b, rand_b);
+ register_cleanup(2, [&table_b] { internal::HashTable::deallocate(table_b); });
+ if (!table_a || !table_b)
+ return 0;
+ for (;;) {
+ Action action = GET_VAL(next_action);
+ switch (action) {
+ case Action::Find: {
+ const char *key = GET_VAL(next_cstr);
+ if (!key)
+ return 0;
+ if (static_cast<bool>(table_a->find(key)) !=
+ static_cast<bool>(table_b->find(key)))
+ trap_with_message(key);
+ break;
+ }
+ case Action::Insert: {
+ char *key = GET_VAL(next_cstr);
+ if (!key)
+ return 0;
+ ENTRY *a = internal::HashTable::insert(table_a, ENTRY{key, key});
+ ENTRY *b = internal::HashTable::insert(table_b, ENTRY{key, key});
+ if (a->data != b->data)
+ __builtin_trap();
+ break;
+ }
+ case Action::CrossCheck: {
+ for (ENTRY a : *table_a) {
+ if (const ENTRY *b = table_b->find(a.key)) {
+ if (a.data != b->data)
+ __builtin_trap();
+ }
+ }
+ for (ENTRY b : *table_b) {
+ if (const ENTRY *a = table_a->find(b.key)) {
+ if (a->data != b.data)
+ __builtin_trap();
+ }
+ }
+ break;
+ }
+ }
+ }
+}
+
+} // namespace LIBC_NAMESPACE
>From 9d681e18e17317d52de705ebf9a332e894971c09 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Sun, 7 Apr 2024 18:35:17 -0400
Subject: [PATCH 2/5] remove extra code
---
libc/fuzzing/__support/hashtable_fuzz.cpp | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/libc/fuzzing/__support/hashtable_fuzz.cpp b/libc/fuzzing/__support/hashtable_fuzz.cpp
index 4b862b03b9d309..758c8d1aae01bf 100644
--- a/libc/fuzzing/__support/hashtable_fuzz.cpp
+++ b/libc/fuzzing/__support/hashtable_fuzz.cpp
@@ -108,9 +108,15 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
uint64_t rand_a = GET_VAL(next_uint64);
uint64_t rand_b = GET_VAL(next_uint64);
internal::HashTable *table_a = internal::HashTable::allocate(size_a, rand_a);
- register_cleanup(1, [&table_a] { internal::HashTable::deallocate(table_a); });
+ register_cleanup(1, [&table_a] {
+ if (table_a)
+ internal::HashTable::deallocate(table_a);
+ });
internal::HashTable *table_b = internal::HashTable::allocate(size_b, rand_b);
- register_cleanup(2, [&table_b] { internal::HashTable::deallocate(table_b); });
+ register_cleanup(2, [&table_b] {
+ if (table_b)
+ internal::HashTable::deallocate(table_b);
+ });
if (!table_a || !table_b)
return 0;
for (;;) {
@@ -118,8 +124,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
switch (action) {
case Action::Find: {
const char *key = GET_VAL(next_cstr);
- if (!key)
- return 0;
if (static_cast<bool>(table_a->find(key)) !=
static_cast<bool>(table_b->find(key)))
trap_with_message(key);
@@ -127,8 +131,6 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
case Action::Insert: {
char *key = GET_VAL(next_cstr);
- if (!key)
- return 0;
ENTRY *a = internal::HashTable::insert(table_a, ENTRY{key, key});
ENTRY *b = internal::HashTable::insert(table_b, ENTRY{key, key});
if (a->data != b->data)
>From 5a72c4d1d63dde2e26f71afa566bc77759188150 Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 8 Apr 2024 09:18:48 -0400
Subject: [PATCH 3/5] make style consistent
---
libc/fuzzing/__support/hashtable_fuzz.cpp | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/libc/fuzzing/__support/hashtable_fuzz.cpp b/libc/fuzzing/__support/hashtable_fuzz.cpp
index 758c8d1aae01bf..d5c64970b53234 100644
--- a/libc/fuzzing/__support/hashtable_fuzz.cpp
+++ b/libc/fuzzing/__support/hashtable_fuzz.cpp
@@ -63,7 +63,7 @@ static cpp::optional<char *> next_cstr() {
return cpp::nullopt;
}
-#define GET_VAL(op) \
+#define get_value(op) \
__extension__({ \
auto val = op(); \
if (!val) \
@@ -103,10 +103,10 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memcpy(global_buffer, data, size);
remaining = size;
- uint64_t size_a = GET_VAL(next_uint64) % 256;
- uint64_t size_b = GET_VAL(next_uint64) % 256;
- uint64_t rand_a = GET_VAL(next_uint64);
- uint64_t rand_b = GET_VAL(next_uint64);
+ uint64_t size_a = get_value(next_uint64) % 256;
+ uint64_t size_b = get_value(next_uint64) % 256;
+ uint64_t rand_a = get_value(next_uint64);
+ uint64_t rand_b = get_value(next_uint64);
internal::HashTable *table_a = internal::HashTable::allocate(size_a, rand_a);
register_cleanup(1, [&table_a] {
if (table_a)
@@ -120,17 +120,17 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (!table_a || !table_b)
return 0;
for (;;) {
- Action action = GET_VAL(next_action);
+ Action action = get_value(next_action);
switch (action) {
case Action::Find: {
- const char *key = GET_VAL(next_cstr);
+ const char *key = get_value(next_cstr);
if (static_cast<bool>(table_a->find(key)) !=
static_cast<bool>(table_b->find(key)))
trap_with_message(key);
break;
}
case Action::Insert: {
- char *key = GET_VAL(next_cstr);
+ char *key = get_value(next_cstr);
ENTRY *a = internal::HashTable::insert(table_a, ENTRY{key, key});
ENTRY *b = internal::HashTable::insert(table_b, ENTRY{key, key});
if (a->data != b->data)
>From 4c87431cb4b53eb7528c406150126a5da585a3ad Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Mon, 8 Apr 2024 12:50:59 -0400
Subject: [PATCH 4/5] make information more concentrated
---
libc/fuzzing/__support/hashtable_fuzz.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/libc/fuzzing/__support/hashtable_fuzz.cpp b/libc/fuzzing/__support/hashtable_fuzz.cpp
index d5c64970b53234..f346d2b79c6db4 100644
--- a/libc/fuzzing/__support/hashtable_fuzz.cpp
+++ b/libc/fuzzing/__support/hashtable_fuzz.cpp
@@ -45,9 +45,9 @@ static cpp::optional<Action> next_action() {
static cpp::optional<char *> next_cstr() {
char *result = reinterpret_cast<char *>(global_buffer);
- if (cpp::optional<uint64_t> len = next_uint64()) {
+ if (cpp::optional<uint8_t> len = next_u8()) {
uint64_t length;
- for (length = 0; length < *len % 128; length++) {
+ for (length = 0; length < *len; length++) {
if (length >= remaining)
return cpp::nullopt;
if (*global_buffer == '\0')
@@ -87,7 +87,7 @@ template <typename Fn> struct CleanUpHook {
#define register_cleanup(ID, ...) \
auto cleanup_hook##ID = __extension__({ \
auto a = __VA_ARGS__; \
- CleanUpHook<decltype(a)>{a}; \
+ CleanUpHook<decltype(a)>(cpp::move(a)); \
});
static void trap_with_message(const char *msg) { __builtin_trap(); }
@@ -103,8 +103,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
memcpy(global_buffer, data, size);
remaining = size;
- uint64_t size_a = get_value(next_uint64) % 256;
- uint64_t size_b = get_value(next_uint64) % 256;
+ uint64_t size_a = get_value(next_u8);
+ uint64_t size_b = get_value(next_u8);
uint64_t rand_a = get_value(next_uint64);
uint64_t rand_b = get_value(next_uint64);
internal::HashTable *table_a = internal::HashTable::allocate(size_a, rand_a);
>From 43486bd306ac6723393a73e36a55ec1141d504db Mon Sep 17 00:00:00 2001
From: Schrodinger ZHU Yifan <yifanzhu at rochester.edu>
Date: Fri, 19 Apr 2024 17:56:50 -0400
Subject: [PATCH 5/5] add missing license headers
---
libc/fuzzing/__support/hashtable_fuzz.cpp | 11 +++++++++++
libc/fuzzing/__support/uint_fuzz.cpp | 11 +++++++++++
2 files changed, 22 insertions(+)
diff --git a/libc/fuzzing/__support/hashtable_fuzz.cpp b/libc/fuzzing/__support/hashtable_fuzz.cpp
index f346d2b79c6db4..4a726b229b7818 100644
--- a/libc/fuzzing/__support/hashtable_fuzz.cpp
+++ b/libc/fuzzing/__support/hashtable_fuzz.cpp
@@ -1,3 +1,14 @@
+//===-- hashtable_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 hashtable implementations.
+///
+//===----------------------------------------------------------------------===//
#include "src/__support/CPP/new.h"
#include "src/__support/CPP/optional.h"
#include "src/__support/HashTable/table.h"
diff --git a/libc/fuzzing/__support/uint_fuzz.cpp b/libc/fuzzing/__support/uint_fuzz.cpp
index 07149f511b8386..109375f84da780 100644
--- a/libc/fuzzing/__support/uint_fuzz.cpp
+++ b/libc/fuzzing/__support/uint_fuzz.cpp
@@ -1,3 +1,14 @@
+//===-- uint_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 unsigned integer utilities.
+///
+//===----------------------------------------------------------------------===//
#include "src/__support/CPP/bit.h"
#include "src/__support/big_int.h"
#include "src/string/memory_utils/inline_memcpy.h"
More information about the libc-commits
mailing list