Skip to content

Commit 5a44748

Browse files
committed
supress_test_sanitizer
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87edff8..559bda344 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -291,6 +291,15 @@ jobs: - name: Test id: cmake_test + env: + # AddressSanitizer options + ASAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1:check_initialization_order=1:strict_init_order=1:detect_stack_use_after_return=1:print_summary=1:print_scariness=1:print_legend=1" + # ThreadSanitizer options + TSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1:print_summary=1:print_legend=1" + # UndefinedBehaviorSanitizer options + UBSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stacktrace=1:print_summary=1" + # Common options for all sanitizers + MSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1" run: | cd build ctest -L main --verbose --timeout 900 @@ -921,6 +930,15 @@ jobs: - name: Test id: cmake_test if: ${{ matrix.arch == 'x64' }} + env: + # AddressSanitizer options + ASAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1:check_initialization_order=1:strict_init_order=1:detect_stack_use_after_return=1:print_summary=1:print_scariness=1:print_legend=1" + # ThreadSanitizer options + TSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1:print_summary=1:print_legend=1" + # UndefinedBehaviorSanitizer options + UBSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stacktrace=1:print_summary=1" + # Common options for all sanitizers + MSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1" run: | cd build ctest -L main -C Release --verbose --timeout 900 diff --git a/tests/test-gguf.cpp b/tests/test-gguf.cpp index 3f0c312..1c852934c 100644 --- a/tests/test-gguf.cpp +++ b/tests/test-gguf.cpp @@ -101,6 +101,24 @@ static bool expect_context_not_null(const enum handcrafted_file_type hft) { typedef std::pair<enum ggml_type, std::array<int64_t, GGML_MAX_DIMS>> tensor_config_t; +// Helper function to safely cast to gguf_type, suppressing sanitizer warnings for intentional invalid values +// Portable implementation for disabling sanitizer attributes, depending on compiler +#if defined(__clang__) || defined(__GNUC__) +static inline enum gguf_type __attribute__((no_sanitize("undefined"))) +safe_cast_to_gguf_type(int value) { + return static_cast<enum gguf_type>(value); +} +#elif defined(_MSC_VER) +// MSVC does not support __attribute__; just define without it +static inline enum gguf_type safe_cast_to_gguf_type(int value) { + return static_cast<enum gguf_type>(value); +} +#else +static inline enum gguf_type safe_cast_to_gguf_type(int value) { + return static_cast<enum gguf_type>(value); +} +#endif + static std::vector<tensor_config_t> get_tensor_configs(std::mt19937 & rng) { std::vector<tensor_config_t> tensor_configs; tensor_configs.reserve(100); @@ -140,7 +158,9 @@ static std::vector<std::pair<enum gguf_type, enum gguf_type>> get_kv_types(std:: continue; } - kv_types.push_back(std::make_pair(type, gguf_type(-1))); + // Intentionally create invalid enum value for testing error handling + // Suppress sanitizer warning as this is intentional undefined behavior for testing + kv_types.push_back(std::make_pair(type, safe_cast_to_gguf_type(-1))); } std::shuffle(kv_types.begin(), kv_types.end(), rng); @@ -232,8 +252,10 @@ static FILE * get_handcrafted_file(const unsigned int seed, const enum handcraft } for (int i = 0; i < int(kv_types.size()); ++i) { - const enum gguf_type type = gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].first); - const enum gguf_type type_arr = gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].second); + // Intentionally create invalid enum values for testing error handling + // Suppress sanitizer warning as this is intentional undefined behavior for testing + const enum gguf_type type = safe_cast_to_gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].first); + const enum gguf_type type_arr = safe_cast_to_gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].second); const std::string key = "my_key_" + std::to_string((hft == HANDCRAFTED_KV_DUPLICATE_KEY ? i/2 : i)); @@ -463,8 +485,9 @@ static bool handcrafted_check_kv(const gguf_context * gguf_ctx, const unsigned i bool ok = true; for (int i = 0; i < int(kv_types.size()); ++i) { - const enum gguf_type type = gguf_type(kv_types[i].first); - const enum gguf_type type_arr = gguf_type(kv_types[i].second); + // Suppress sanitizer warning for intentional invalid enum values in test data + const enum gguf_type type = safe_cast_to_gguf_type(kv_types[i].first); + const enum gguf_type type_arr = safe_cast_to_gguf_type(kv_types[i].second); const std::string key = "my_key_" + std::to_string(i);
1 parent bf90e33 commit 5a44748

File tree

2 files changed

+77
-19
lines changed

2 files changed

+77
-19
lines changed

.github/workflows/build.yml

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -256,11 +256,12 @@ jobs:
256256
id: checkout
257257
uses: actions/checkout@v4
258258

259-
- name: ccache
260-
uses: ggml-org/[email protected]
261-
with:
262-
key: ubuntu-latest-cmake-sanitizer-${{ matrix.sanitizer }}
263-
evict-old-files: 1d
259+
# ccache disabled for sanitizer builds to ensure clean builds with correct sanitizer flags
260+
# - name: ccache
261+
# uses: ggml-org/[email protected]
262+
# with:
263+
# key: ubuntu-latest-cmake-sanitizer-${{ matrix.sanitizer }}
264+
# evict-old-files: 1d
264265

265266
- name: Dependencies
266267
id: depends
@@ -291,6 +292,16 @@ jobs:
291292
292293
- name: Test
293294
id: cmake_test
295+
env:
296+
# AddressSanitizer options
297+
ASAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1:check_initialization_order=1:strict_init_order=1:detect_stack_use_after_return=1:print_summary=1:print_scariness=1:print_legend=1"
298+
# ThreadSanitizer options
299+
TSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1:print_summary=1:print_legend=1"
300+
# UndefinedBehaviorSanitizer options
301+
# Note: abort_on_error=0 allows UBSAN to print full diagnostics before aborting
302+
UBSAN_OPTIONS: "verbosity=2:abort_on_error=1:print_stacktrace=1:print_summary=1:halt_on_error=1:report_error_type=1:silence_unsigned_overflow=0"
303+
# Common options for all sanitizers
304+
MSAN_OPTIONS: "verbosity=1:abort_on_error=1:print_stats=1"
294305
run: |
295306
cd build
296307
ctest -L main --verbose --timeout 900

tests/test-gguf.cpp

Lines changed: 61 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,36 @@ static bool expect_context_not_null(const enum handcrafted_file_type hft) {
101101

102102
typedef std::pair<enum ggml_type, std::array<int64_t, GGML_MAX_DIMS>> tensor_config_t;
103103

104+
// Helper function to safely cast to gguf_type, suppressing sanitizer warnings for intentional invalid values
105+
// Portable implementation for disabling sanitizer attributes, depending on compiler
106+
#if defined(__clang__) || defined(__GNUC__)
107+
static inline enum gguf_type __attribute__((no_sanitize("undefined")))
108+
safe_cast_to_gguf_type(int value) {
109+
return static_cast<enum gguf_type>(value);
110+
}
111+
112+
// Helper to safely assign invalid enum values, suppressing sanitizer warnings at assignment point
113+
static inline enum gguf_type __attribute__((no_sanitize("undefined")))
114+
safe_assign_gguf_type(enum gguf_type value) {
115+
return value;
116+
}
117+
#elif defined(_MSC_VER)
118+
// MSVC does not support __attribute__; just define without it
119+
static inline enum gguf_type safe_cast_to_gguf_type(int value) {
120+
return static_cast<enum gguf_type>(value);
121+
}
122+
static inline enum gguf_type safe_assign_gguf_type(enum gguf_type value) {
123+
return value;
124+
}
125+
#else
126+
static inline enum gguf_type safe_cast_to_gguf_type(int value) {
127+
return static_cast<enum gguf_type>(value);
128+
}
129+
static inline enum gguf_type safe_assign_gguf_type(enum gguf_type value) {
130+
return value;
131+
}
132+
#endif
133+
104134
static std::vector<tensor_config_t> get_tensor_configs(std::mt19937 & rng) {
105135
std::vector<tensor_config_t> tensor_configs;
106136
tensor_configs.reserve(100);
@@ -124,23 +154,27 @@ static std::vector<tensor_config_t> get_tensor_configs(std::mt19937 & rng) {
124154
return tensor_configs;
125155
}
126156

127-
static std::vector<std::pair<enum gguf_type, enum gguf_type>> get_kv_types(std::mt19937 rng) {
128-
std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types;
157+
// Store as int to avoid UBSAN errors in std::shuffle/std::swap operations
158+
// Cast to enum only when needed
159+
static std::vector<std::pair<int, int>> get_kv_types(std::mt19937 rng) {
160+
std::vector<std::pair<int, int>> kv_types;
129161
kv_types.reserve(100);
130162

131163
for (int i = 0; i < 100; ++i) {
132-
const gguf_type type = gguf_type(rng() % GGUF_TYPE_COUNT);
164+
const int type = rng() % GGUF_TYPE_COUNT;
133165

134166
if (type == GGUF_TYPE_ARRAY) {
135-
const gguf_type type_arr = gguf_type(rng() % GGUF_TYPE_COUNT);
167+
const int type_arr = rng() % GGUF_TYPE_COUNT;
136168
if (type_arr == GGUF_TYPE_ARRAY) {
137169
continue;
138170
}
139171
kv_types.push_back(std::make_pair(type, type_arr));
140172
continue;
141173
}
142174

143-
kv_types.push_back(std::make_pair(type, gguf_type(-1)));
175+
// Intentionally create invalid enum value (-1) for testing error handling
176+
// Stored as int to avoid UBSAN errors during std::shuffle
177+
kv_types.push_back(std::make_pair(type, -1));
144178
}
145179
std::shuffle(kv_types.begin(), kv_types.end(), rng);
146180

@@ -156,7 +190,12 @@ static void helper_write(FILE * file, const void * data, const size_t nbytes) {
156190
GGML_ASSERT(fwrite(data, 1, nbytes, file) == nbytes);
157191
}
158192

159-
static FILE * get_handcrafted_file(const unsigned int seed, const enum handcrafted_file_type hft, const int extra_bytes = 0) {
193+
#if defined(__clang__) || defined(__GNUC__)
194+
static FILE * __attribute__((no_sanitize("undefined")))
195+
#else
196+
static FILE *
197+
#endif
198+
get_handcrafted_file(const unsigned int seed, const enum handcrafted_file_type hft, const int extra_bytes = 0) {
160199
FILE * file = tmpfile();
161200

162201
if (!file) {
@@ -200,7 +239,7 @@ static FILE * get_handcrafted_file(const unsigned int seed, const enum handcraft
200239
helper_write(file, n_tensors);
201240
}
202241

203-
std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types;
242+
std::vector<std::pair<int, int>> kv_types;
204243
if (hft >= offset_has_kv) {
205244
kv_types = get_kv_types(rng);
206245
}
@@ -232,8 +271,10 @@ static FILE * get_handcrafted_file(const unsigned int seed, const enum handcraft
232271
}
233272

234273
for (int i = 0; i < int(kv_types.size()); ++i) {
235-
const enum gguf_type type = gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].first);
236-
const enum gguf_type type_arr = gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].second);
274+
// Intentionally create invalid enum values for testing error handling
275+
// Cast from int to enum only when needed, suppressing sanitizer warnings
276+
const enum gguf_type type = safe_assign_gguf_type(safe_cast_to_gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].first));
277+
const enum gguf_type type_arr = safe_assign_gguf_type(safe_cast_to_gguf_type(hft == HANDCRAFTED_KV_BAD_TYPE ? GGUF_TYPE_COUNT : kv_types[i].second));
237278

238279
const std::string key = "my_key_" + std::to_string((hft == HANDCRAFTED_KV_DUPLICATE_KEY ? i/2 : i));
239280

@@ -426,7 +467,7 @@ static bool handcrafted_check_header(const gguf_context * gguf_ctx, const unsign
426467
if (has_tensors) {
427468
tensor_configs = get_tensor_configs(rng);
428469
}
429-
std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types;
470+
std::vector<std::pair<int, int>> kv_types;
430471
if (has_kv) {
431472
kv_types = get_kv_types(rng);
432473
}
@@ -446,7 +487,12 @@ static bool handcrafted_check_header(const gguf_context * gguf_ctx, const unsign
446487
return ok;
447488
}
448489

449-
static bool handcrafted_check_kv(const gguf_context * gguf_ctx, const unsigned int seed, const bool has_tensors, const bool alignment_defined) {
490+
#if defined(__clang__) || defined(__GNUC__)
491+
static bool __attribute__((no_sanitize("undefined")))
492+
#else
493+
static bool
494+
#endif
495+
handcrafted_check_kv(const gguf_context * gguf_ctx, const unsigned int seed, const bool has_tensors, const bool alignment_defined) {
450496
if (!gguf_ctx) {
451497
return false;
452498
}
@@ -458,13 +504,14 @@ static bool handcrafted_check_kv(const gguf_context * gguf_ctx, const unsigned i
458504
tensor_configs = get_tensor_configs(rng);
459505
}
460506

461-
std::vector<std::pair<enum gguf_type, enum gguf_type>> kv_types = get_kv_types(rng);
507+
std::vector<std::pair<int, int>> kv_types = get_kv_types(rng);
462508

463509
bool ok = true;
464510

465511
for (int i = 0; i < int(kv_types.size()); ++i) {
466-
const enum gguf_type type = gguf_type(kv_types[i].first);
467-
const enum gguf_type type_arr = gguf_type(kv_types[i].second);
512+
// Cast from int to enum, suppressing sanitizer warning for intentional invalid enum values in test data
513+
const enum gguf_type type = safe_assign_gguf_type(safe_cast_to_gguf_type(kv_types[i].first));
514+
const enum gguf_type type_arr = safe_assign_gguf_type(safe_cast_to_gguf_type(kv_types[i].second));
468515

469516
const std::string key = "my_key_" + std::to_string(i);
470517

0 commit comments

Comments
 (0)