Skip to content

Commit 62476a1

Browse files
committed
xAdd fuzz tests
1 parent 7e4e2fa commit 62476a1

File tree

6 files changed

+347
-4
lines changed

6 files changed

+347
-4
lines changed

.github/workflows/nightly.yml

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,53 @@
22
name: Nightly
33

44
# This job is run at 00:00 UTC every day or on demand.
5-
on:
6-
workflow_dispatch:
7-
schedule:
8-
- cron: '0 0 * * *'
5+
on: [workflow_call]
96

107
permissions:
118
contents: read
129

1310
jobs:
11+
fuzz-test:
12+
name: Fuzz test
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
build_type: [Debug, Release]
17+
compiler: [{c: clang, cxx: clang++}]
18+
19+
runs-on: ubuntu-latest
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
24+
25+
- name: Install apt packages
26+
run: |
27+
sudo apt-get update
28+
sudo apt-get install -y cmake hwloc libhwloc-dev libjemalloc-dev libnuma-dev libtbb-dev
29+
30+
- name: Configure CMake
31+
run: >
32+
cmake
33+
-B ${{github.workspace}}/build
34+
-DCMAKE_BUILD_TYPE=${{matrix.build_type}}
35+
-DCMAKE_C_COMPILER=${{matrix.compiler.c}}
36+
-DCMAKE_CXX_COMPILER=${{matrix.compiler.cxx}}
37+
-DUMF_FORMAT_CODE_STYLE=ON
38+
-DUMF_TESTS_FAIL_ON_SKIP=ON
39+
-DUMF_DEVELOPER_MODE=ON
40+
41+
- name: Build
42+
run: cmake --build ${{github.workspace}}/build --config ${{matrix.build_type}} -j$(nproc)
43+
44+
- name: Fuzz short test
45+
working-directory: ${{github.workspace}}/build
46+
run: ctest -C Debug --output-on-failure -L "fuzz-short"
47+
48+
- name: Fuzz long test
49+
working-directory: ${{github.workspace}}/build
50+
run: ctest -C Debug --output-on-failure -L "fuzz-long"
51+
1452
valgrind:
1553
name: Valgrind
1654
strategy:

.github/workflows/pr_push.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,3 +205,5 @@ jobs:
205205
MultiNuma:
206206
needs: [Build]
207207
uses: ./.github/workflows/multi_numa.yml
208+
Nightly:
209+
uses: ./.github/workflows/nightly.yml

test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ if(LINUX) # OS-specific functions are implemented only for Linux now
187187
NAME mempolicy
188188
SRCS memspaces/mempolicy.cpp
189189
LIBS ${LIBNUMA_LIBRARIES})
190+
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
191+
add_subdirectory(fuzz)
192+
endif()
190193
endif()
191194

192195
if(UMF_BUILD_GPU_TESTS AND UMF_BUILD_LEVEL_ZERO_PROVIDER)

test/fuzz/CMakeLists.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Copyright (C) 2024 Intel Corporation
2+
# Part of the Unified-Runtime Project, under the Apache License v2.0 with LLVM Exceptions.
3+
# See LICENSE.TXT
4+
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
6+
function(add_fuzz_test name label)
7+
add_test(
8+
NAME ${name}
9+
COMMAND fuzz_test-base ${ARGN} -verbosity=1
10+
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
11+
set_tests_properties(${name} PROPERTIES LABELS ${label})
12+
endfunction()
13+
14+
set(TEST_TARGET_NAME fuzz_test-base)
15+
add_umf_executable(
16+
NAME ${TEST_TARGET_NAME}
17+
SRCS umfFuzz.cpp
18+
LIBS umf)
19+
target_link_libraries(${TEST_TARGET_NAME} PRIVATE umf -fsanitize=fuzzer)
20+
target_compile_options(${TEST_TARGET_NAME} PRIVATE -g -fsanitize=fuzzer)
21+
target_include_directories(${TEST_TARGET_NAME}
22+
PRIVATE ${UMF_CMAKE_SOURCE_DIR}/include)
23+
target_link_directories(${TEST_TARGET_NAME} PRIVATE ${LIBHWLOC_LIBRARY_DIRS})
24+
25+
add_fuzz_test(base_long fuzz-long -max_total_time=600 -seed=1)
26+
add_fuzz_test(base_short fuzz-short -max_total_time=10 -seed=1)

test/fuzz/umfFuzz.cpp

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
// Copyright (C) 2024 Intel Corporation
2+
// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#include "utils.hpp"
6+
#include <iostream>
7+
8+
namespace fuzz {
9+
10+
constexpr int MAX_PROVIDER_VECTOR_SIZE = 1024;
11+
constexpr int MAX_POOLS_VECTOR_SIZE = 20;
12+
constexpr int MAX_POOLS_ALLOC_SIZE = 1 * 1024; // 1 kB
13+
constexpr int MAX_PROVIDER_ALLOC_SIZE = 100 * 1024; // 100 kB
14+
15+
int umf_memory_provider_create(TestState &test_state) {
16+
std::cout << "begin umf_memory_provider_create" << std::endl;
17+
umf_memory_provider_ops_t *provider_ops = umfOsMemoryProviderOps();
18+
umf_os_memory_provider_params_t params = umfOsMemoryProviderParamsDefault();
19+
umf_result_t res =
20+
umfMemoryProviderCreate(provider_ops, &params, &test_state.provider);
21+
22+
if (res != UMF_RESULT_SUCCESS) {
23+
std::cout << "Failed to create a memory provider! " << res << std::endl;
24+
return -1;
25+
}
26+
std::cout << "OS memory provider created at " << (void *)test_state.provider
27+
<< std::endl;
28+
return 0;
29+
}
30+
31+
int get_alloc_size(TestState &state, size_t &alloc_size, int max_alloc_size) {
32+
if (state.get_next_input_data_in_range<size_t>(&alloc_size, 0,
33+
max_alloc_size) != 0) {
34+
return -1;
35+
}
36+
return 0;
37+
}
38+
39+
int umf_memory_provider_alloc(TestState &test_state) {
40+
std::cout << "begin umf_memory_provider_alloc" << std::endl;
41+
void *ptr;
42+
size_t alloc_size;
43+
constexpr size_t alignment = 0;
44+
45+
if (test_state.allocated_memory.size() >= MAX_PROVIDER_VECTOR_SIZE) {
46+
return -1;
47+
}
48+
49+
int ret = get_alloc_size(test_state, alloc_size, MAX_PROVIDER_ALLOC_SIZE);
50+
if (ret != 0) {
51+
return -1;
52+
}
53+
54+
umf_result_t res = umfMemoryProviderAlloc(test_state.provider, alloc_size,
55+
alignment, &ptr);
56+
if (res != UMF_RESULT_SUCCESS) {
57+
std::cout << "Failed to create a memory provider! " << res << std::endl;
58+
return -1;
59+
}
60+
test_state.allocated_memory.push_back(std::make_pair(ptr, alloc_size));
61+
std::cout << "Allocated memory at " << ptr << " with alloc_size "
62+
<< alloc_size << std::endl;
63+
std::cout << "Vector size is: " << test_state.allocated_memory.size()
64+
<< std::endl;
65+
return 0;
66+
}
67+
68+
int umf_memory_provider_free(TestState &test_state) {
69+
printf("begin umf_memory_provider_free\n");
70+
if (test_state.allocated_memory.empty()) {
71+
return -1;
72+
}
73+
74+
std::pair<void *, size_t> alloc = test_state.allocated_memory.back();
75+
umf_result_t res =
76+
umfMemoryProviderFree(test_state.provider, alloc.first, alloc.second);
77+
78+
if (res != UMF_RESULT_SUCCESS) {
79+
std::cout << "Failed to free memory to the provider! " << res
80+
<< std::endl;
81+
;
82+
return -1;
83+
}
84+
85+
std::cout << "Freed memory at " << alloc.first << " with alloc_size "
86+
<< alloc.second << std::endl;
87+
test_state.allocated_memory.pop_back();
88+
return 0;
89+
}
90+
91+
int umf_pool_create(TestState &test_state) {
92+
if (test_state.pools.size() > MAX_POOLS_VECTOR_SIZE) {
93+
return -1;
94+
}
95+
96+
umf_memory_pool_ops_t *pool_ops = umfScalablePoolOps();
97+
void *pool_params = NULL;
98+
umf_pool_create_flags_t flags = 0;
99+
umf_memory_pool_handle_t pool;
100+
umf_result_t res =
101+
umfPoolCreate(pool_ops, test_state.provider, pool_params, flags, &pool);
102+
103+
if (res != UMF_RESULT_SUCCESS) {
104+
std::cout << "Failed to create a pool! " << res << std::endl;
105+
return -1;
106+
}
107+
108+
test_state.pools.push_back(pool);
109+
std::cout << "Scalable memory pool created at " << pool
110+
<< "and Pools' vector size is: " << test_state.pools.size()
111+
<< std::endl;
112+
return 0;
113+
}
114+
115+
int umf_pool_destroy(TestState &test_state) {
116+
if (test_state.pools.empty()) {
117+
return -1;
118+
}
119+
umfPoolDestroy(test_state.pools.back());
120+
test_state.pools.pop_back();
121+
return 0;
122+
}
123+
124+
int umf_pool_malloc(TestState &test_state) {
125+
if (test_state.pools.empty()) {
126+
return -1;
127+
}
128+
size_t alloc_size;
129+
int ret = get_alloc_size(test_state, alloc_size, MAX_POOLS_ALLOC_SIZE);
130+
if (ret != 0) {
131+
return -1;
132+
}
133+
134+
void *ptr = umfPoolMalloc(test_state.pools.back(), alloc_size);
135+
if (!ptr) {
136+
std::cout << "Failed to allocate memory in the pool!" << std::endl;
137+
return -1;
138+
}
139+
test_state.pools_alloc.push_back(ptr);
140+
return 0;
141+
}
142+
143+
int umf_free(TestState &test_state) {
144+
if (test_state.pools_alloc.empty()) {
145+
return -1;
146+
}
147+
umfFree(test_state.pools_alloc.back());
148+
test_state.pools_alloc.pop_back();
149+
return 0;
150+
}
151+
152+
void cleanup(TestState &test_state) {
153+
for (auto &alloc : test_state.allocated_memory) {
154+
umfMemoryProviderFree(test_state.provider, alloc.first, alloc.second);
155+
}
156+
std::cout << "Freed all allocated memory\n";
157+
158+
for (auto &alloc : test_state.pools_alloc) {
159+
umfFree(alloc);
160+
}
161+
for (auto &pool : test_state.pools) {
162+
umfPoolDestroy(pool);
163+
}
164+
165+
umfMemoryProviderDestroy(test_state.provider);
166+
}
167+
168+
extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
169+
int next_api_call;
170+
auto data_provider = std::make_unique<FuzzedDataProvider>(data, size);
171+
TestState test_state(std::move(data_provider));
172+
int ret = -1;
173+
174+
int (*api_wrappers[])(TestState &) = {
175+
umf_memory_provider_alloc, umf_memory_provider_free, umf_pool_create,
176+
umf_pool_destroy, umf_pool_malloc, umf_free,
177+
};
178+
umf_memory_provider_create(test_state);
179+
180+
while ((next_api_call = test_state.get_next_api_call()) != -1) {
181+
ret = api_wrappers[next_api_call](test_state);
182+
if (ret) {
183+
cleanup(test_state);
184+
return -1;
185+
}
186+
}
187+
188+
cleanup(test_state);
189+
return 0;
190+
}
191+
} // namespace fuzz

test/fuzz/utils.hpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// Copyright (C) 2024 Intel Corporation
2+
// Under the Apache License v2.0 with LLVM Exceptions. See LICENSE.TXT.
3+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4+
5+
#include "umf/pools/pool_scalable.h"
6+
#include "umf/providers/provider_os_memory.h"
7+
#include <fuzzer/FuzzedDataProvider.h>
8+
#include <iostream>
9+
#include <memory>
10+
#include <vector>
11+
12+
namespace fuzz {
13+
14+
enum FuzzerAPICall : uint8_t {
15+
UMF_MEMORY_PROVIDER_ALLOC,
16+
UMF_MEMORY_PROVIDER_FREE,
17+
UMF_POOL_CREATE,
18+
UMF_POOL_DESTROY,
19+
UMF_POOL_MALLOC,
20+
UMF_POOL_FREE,
21+
kMaxValue = UMF_POOL_FREE,
22+
};
23+
24+
struct TestState {
25+
std::unique_ptr<FuzzedDataProvider> data_provider;
26+
umf_memory_provider_handle_t provider;
27+
std::vector<std::pair<void *, size_t>> allocated_memory; //provider
28+
std::vector<umf_memory_pool_handle_t> pools;
29+
std::vector<void *> pools_alloc; //pool
30+
31+
TestState(std::unique_ptr<FuzzedDataProvider> data_provider)
32+
: data_provider(std::move(data_provider)) {}
33+
34+
template <typename IntType> int get_next_input_data(IntType *data) {
35+
if (data_provider->remaining_bytes() < sizeof(IntType)) {
36+
return -1;
37+
}
38+
*data = data_provider->ConsumeIntegral<IntType>();
39+
40+
return 0;
41+
}
42+
43+
template <typename IntType>
44+
int get_next_input_data_in_range(IntType *data, IntType min, IntType max) {
45+
if (data_provider->remaining_bytes() < sizeof(IntType)) {
46+
return -1;
47+
}
48+
*data = data_provider->ConsumeIntegralInRange<IntType>(min, max);
49+
50+
return 0;
51+
}
52+
53+
template <typename EnumType> int get_next_input_data_enum(EnumType *data) {
54+
if (data_provider->remaining_bytes() < sizeof(EnumType)) {
55+
return -1;
56+
}
57+
*data = data_provider->ConsumeEnum<EnumType>();
58+
59+
return 0;
60+
}
61+
62+
int init() { return 0; }
63+
64+
int get_next_api_call() {
65+
FuzzerAPICall next_api_call;
66+
return get_next_input_data_enum(&next_api_call) == 0 ? next_api_call
67+
: -1;
68+
}
69+
70+
umf_memory_provider_handle_t get_memory_provider() { return nullptr; }
71+
72+
int get_vec_index(const uint8_t vec_size) {
73+
if (vec_size == 0 ||
74+
data_provider->remaining_bytes() < sizeof(vec_size)) {
75+
return -1;
76+
}
77+
return data_provider->ConsumeIntegralInRange<decltype(vec_size)>(
78+
0, vec_size - 1);
79+
}
80+
81+
size_t get_next_alloc_size() { return 0; }
82+
};
83+
} // namespace fuzz

0 commit comments

Comments
 (0)