tests: replace fuzzer with exaustive test

Tests the entire 32-bit instruction space (4.29B).

Signed-off-by: Ronald Caesar <github43132@proton.me>
This commit is contained in:
Ronald Caesar
2026-01-18 05:24:17 -04:00
parent 3b9703f316
commit 98992b54c3
3 changed files with 123 additions and 84 deletions

View File

@@ -120,9 +120,8 @@ endif()
if (BALLISTIC_ENABLE_BUILD_TESTS)
set(TESTS_NAME "ballistic_tests")
enable_testing()
add_executable(${TESTS_NAME} tests/test_decoder_fuzzer.c)
add_executable(${TESTS_NAME} tests/test_decoder.c)
target_include_directories(${TESTS_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
target_link_libraries(${TESTS_NAME} PRIVATE ${PROJECT_NAME})
add_test(NAME DecoderTest COMMAND ${TESTS_NAME})
endif()

121
tests/test_decoder.c Normal file
View File

@@ -0,0 +1,121 @@
#include "bal_decoder.h"
#include "decoder_table_gen.h"
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
#if defined(_MSC_VER)
#include <intrin.h>
#define POPCOUNT(x) __popcnt(x)
#else
#define POPCOUNT(x) __builtin_popcount(x)
#endif
#define DECODER_HASH_SHIFT 21
#define DECODER_HASH_MASK 0x7FF
int
main (void)
{
printf("Starting Decoder Test (0x00000000 - 0xFFFFFFFF)...\n");
uint64_t total_decoded = 0;
uint64_t total_collisions = 0;
uint64_t total_errors = 0;
for (uint64_t i = 0; i <= UINT32_MAX; ++i)
{
uint32_t instruction = (uint32_t)i;
const bal_decoder_instruction_metadata_t *metadata
= bal_decoder_arm64_decode(instruction);
uint32_t hash_index = (instruction >> DECODER_HASH_SHIFT) & DECODER_HASH_MASK;
const decoder_bucket_t *bucket = &g_decoder_lookup_table[hash_index];
const bal_decoder_instruction_metadata_t *best_match = NULL;
int max_priority = -1;
if (bucket->instructions != NULL)
{
for (size_t j = 0; j < bucket->count; ++j)
{
const bal_decoder_instruction_metadata_t *candidate = bucket->instructions[j];
if (candidate->expected == (instruction & candidate->mask))
{
int priority = POPCOUNT(candidate->mask);
if (priority > max_priority)
{
max_priority = priority;
best_match = candidate;
}
else
{
// Two instructions with equal priority claim these bits.
// There is a bug in the XML parser.
//
if (best_match && strcmp(best_match->name, candidate->name) != 0)
{
++total_collisions;
}
}
}
}
}
if (metadata != best_match)
{
printf("[FAIL] Priority Error at 0x%08x\n", instruction);
printf(" Decoder returned: %s\n", metadata ? metadata->name : "NULL");
printf(" Reference found: %s\n", best_match ? best_match->name : "NULL");
if (metadata != NULL)
{
printf(" Decoder Mask: 0x%08x (Priority: %d)\n", metadata->mask, POPCOUNT(metadata->mask));
}
if (best_match != NULL)
{
printf(" Ref Mask: 0x%08x (Priority: %d)\n", best_match->mask, POPCOUNT(best_match->mask));
}
++total_errors;
if (total_errors > 10)
{
printf("[FATAL] Too many errors. Aborting...");
return 1;
}
}
if (metadata != NULL)
{
// The decoder should never return a match that failed the mask.
if ((instruction & metadata->mask) != metadata->expected)
{
printf("[FAIL] Consistency: Inst 0x%08x matched '%s' but failed mask check.\n", instruction, metadata->name);
++total_errors;
}
++total_decoded;
}
if (0 == (instruction & 0x0FFFFFFF))
{
printf("Progress: %3.0f%% (0x%08x)\n", (double)i / 42949672.96, instruction);
}
}
printf("--- Results ---\n");
printf("Total Decoded: %" PRIu64 "\n", total_decoded);
printf("Total Collisions: %" PRIu64 "\n", total_collisions);
printf("Total Errors: %" PRIu64 "\n", total_errors);
if (total_errors > 0)
{
printf("[FAILURE] Ballistic Decoder is flawed.\n");
return 1;
}
printf("[SUCCESS] Ballistic Decoder is mathematically correct.\n");
return 0;
}

View File

@@ -1,81 +0,0 @@
#include "bal_decoder.h"
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdint.h>
#include <time.h>
static uint32_t rng_state = 0x87654321;
/*
* Seeding function to set the initial state.
*/
static void
fast_srand (uint32_t seed)
{
if (seed == 0)
{
seed = 0x87654321;
}
rng_state = seed;
}
/*
* Xorshift32 Algorithm
*/
static inline uint32_t
fast_rand (void)
{
uint32_t x = rng_state;
x ^= x << 13;
x ^= x >> 17;
x ^= x << 5;
rng_state = x;
return x;
}
int
main (void)
{
printf("Starting Decoder Fuzzer Test...\n");
fast_srand((uint32_t)time(0));
int failed = 0;
int passed = 0;
for (size_t i = 0; i < 10000000; ++i)
{
uint32_t random_instruction = fast_rand();
const bal_decoder_instruction_metadata_t *meta
= bal_decoder_arm64_decode(random_instruction);
if (NULL != meta)
{
if ((random_instruction & meta->mask) != meta->expected)
{
printf("[FAIL] %s, 0x%08x & 0x%08x != 0x%08x",
meta->name,
random_instruction,
meta->mask,
meta->expected);
++failed;
continue;
}
++passed;
}
}
if (failed > 0)
{
printf("FAILED %d tests. \n", failed);
return 1;
}
if (passed > 0)
{
printf("Decoded %d instructions successfully\n", passed);
return 0;
}
else
{
printf("[ERROR] No tests passed or failed. Ballistic's decoding logic is flawed\n");
}
}