Files
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

239 lines
7.8 KiB
C++

/* ************************************************************************
* Copyright (C) 2025-2026 Advanced Micro Devices, Inc.
************************************************************************ */
/**
* Fuzzing-style tests for parsers
*
* These tests throw edge-case inputs at parsers to ensure they never crash.
* Think of this as "manual fuzzing" - we test patterns a fuzzer would find.
*/
#include <gtest/gtest.h>
#include <cstdio>
#include <filesystem>
#include <fstream>
#include "stinkytofu/serialization/asm/IRParser.hpp"
#include "stinkytofu/serialization/asm/PatternParser.hpp"
using namespace stinkytofu;
class FuzzTest : public ::testing::Test {
protected:
// Helper to parse pattern from string
PatternParseResult parsePatternString(const std::string& input) {
auto tmpPath = std::filesystem::temp_directory_path() / "fuzz_test.pattern";
std::ofstream out(tmpPath);
out << input;
out.close();
auto result = parsePatternFileWithDiagnostics(tmpPath.string().c_str());
std::filesystem::remove(tmpPath);
return result;
}
};
// ============================================================================
// IRParser Fuzz Tests
// ============================================================================
TEST_F(FuzzTest, IRParserHandlesEmptyInput) {
auto result = parseSourceStringWithDiagnostics("");
// Should not crash, diagnostics may or may not be present
EXPECT_TRUE(true); // Survived!
}
TEST_F(FuzzTest, IRParserHandlesVeryLongInput) {
// FIXED! Previously crashed with assertion failure
// Now stringToRegType() returns UNKNOWN instead of asserting
std::string input(100000, 'v');
auto result = parseSourceStringWithDiagnostics(input);
// Should not crash, even on 100KB of 'v's
// Parser should handle gracefully (may produce errors or parse what it can)
EXPECT_TRUE(true); // Main goal: no crash
}
TEST_F(FuzzTest, IRParserHandlesRepeatedSymbols) {
std::string input = std::string(1000, '[') + std::string(1000, ']');
auto result = parseSourceStringWithDiagnostics(input);
EXPECT_TRUE(true);
}
TEST_F(FuzzTest, IRParserHandlesNullBytes) {
std::string input = "v[0]\x00\x00\x00";
auto result = parseSourceStringWithDiagnostics(input);
EXPECT_TRUE(true);
}
TEST_F(FuzzTest, IRParserHandlesUnicode) {
std::string input = "v[0] = ???";
auto result = parseSourceStringWithDiagnostics(input);
// Should produce error but not crash
EXPECT_TRUE(result.hasErrors() || result.getInstructions().empty());
}
TEST_F(FuzzTest, IRParserHandlesDeepNesting) {
std::string input = "v[0] = \"st.v_add_f32\"(";
for (int i = 0; i < 100; i++) {
input += "v[" + std::to_string(i) + "], ";
}
input += "v[100])";
auto result = parseSourceStringWithDiagnostics(input);
EXPECT_TRUE(true); // Didn't crash
}
TEST_F(FuzzTest, IRParserHandlesLargeNumbers) {
// FIXED! Previously threw std::out_of_range exception
// Now uses safeStoi() which catches exceptions and returns error
auto result = parseSourceStringWithDiagnostics("v[999999999999999999]");
// Should produce error, not crash or throw
EXPECT_TRUE(result.hasErrors());
EXPECT_GT(result.diagnostics.size(), 0);
EXPECT_TRUE(result.getInstructions().empty());
}
TEST_F(FuzzTest, IRParserHandlesManyQuotes) {
std::string input = "v[0] = " + std::string(1000, '"');
auto result = parseSourceStringWithDiagnostics(input);
EXPECT_TRUE(true);
}
TEST_F(FuzzTest, IRParserValidatesDiagnosticInvariants) {
// Test various bad inputs
std::vector<std::string> badInputs = {
"v[0] = ", "v[0] = (", "v[0] = \"st.v_add_f32\"(", "[[[[", "v[0] v[1] v[2]",
};
for (const auto& input : badInputs) {
auto result = parseSourceStringWithDiagnostics(input);
// Validate diagnostic invariants
for (const auto& diag : result.diagnostics) {
// Line and column must be positive
EXPECT_GT(diag.getLine(), 0) << "For input: " << input;
EXPECT_GT(diag.getColumn(), 0) << "For input: " << input;
// Message must not be empty
EXPECT_FALSE(diag.getMessage().empty()) << "For input: " << input;
}
}
}
// ============================================================================
// PatternParser Fuzz Tests
// ============================================================================
TEST_F(FuzzTest, PatternParserHandlesEmptyInput) {
auto result = parsePatternString("");
EXPECT_TRUE(true); // Didn't crash
}
TEST_F(FuzzTest, PatternParserHandlesVeryLongInput) {
std::string input = "peephole pattern " + std::string(10000, 'A') + " { }";
auto result = parsePatternString(input);
EXPECT_TRUE(true);
}
TEST_F(FuzzTest, PatternParserHandlesUnbalancedBraces) {
std::vector<std::string> inputs = {
"peephole pattern Test { { { { ",
"} } } } }",
"peephole pattern Test { match { } } } }",
};
for (const auto& input : inputs) {
auto result = parsePatternString(input);
EXPECT_TRUE(true); // Didn't crash
}
}
TEST_F(FuzzTest, PatternParserHandlesInvalidKeywords) {
std::string input = R"(
invalid_keyword pattern Test {
invalid_block { $x = v_add_f32 $a, $b }
another_invalid { }
}
)";
auto result = parsePatternString(input);
EXPECT_TRUE(true);
}
TEST_F(FuzzTest, PatternParserHandlesManyPatterns) {
std::string input;
for (int i = 0; i < 1000; i++) {
input += "peephole pattern Pattern" + std::to_string(i) + " { }\n";
}
auto result = parsePatternString(input);
EXPECT_TRUE(true); // Didn't crash on 1000 patterns
}
TEST_F(FuzzTest, PatternParserValidatesDiagnosticInvariants) {
std::vector<std::string> badInputs = {
"peephole pattern { }",
"peephole pattern Test {",
"intrinsic Test { arguments { } }",
"{ } { } { }",
};
for (const auto& input : badInputs) {
auto result = parsePatternString(input);
// Validate diagnostic invariants
for (const auto& diag : result.diagnostics) {
EXPECT_GT(diag.getLine(), 0) << "For input: " << input;
EXPECT_GT(diag.getColumn(), 0) << "For input: " << input;
EXPECT_FALSE(diag.getMessage().empty()) << "For input: " << input;
}
}
}
// ============================================================================
// Stress Tests
// ============================================================================
TEST_F(FuzzTest, IRParserStressTest) {
// Generate many random-ish inputs
std::vector<std::string> inputs;
// Valid-looking but with errors
for (int i = 0; i < 100; i++) {
inputs.push_back("v[" + std::to_string(i) + "] = \"st.v_add_f32\"(");
inputs.push_back("v[" + std::to_string(i) + "]");
inputs.push_back("= \"st.v_add_f32\"()");
}
// Parse all of them - parsers should never crash
for (const auto& input : inputs) {
auto result = parseSourceStringWithDiagnostics(input);
// If we get here, parser didn't crash - good!
}
EXPECT_TRUE(true) << "Parser survived all " << inputs.size() << " inputs";
}
TEST_F(FuzzTest, PatternParserStressTest) {
std::vector<std::string> inputs;
// Generate many malformed patterns
for (int i = 0; i < 100; i++) {
inputs.push_back("peephole pattern Test" + std::to_string(i) + " {");
inputs.push_back("intrinsic Test" + std::to_string(i) + " { arguments");
inputs.push_back("{ } pattern { } intrinsic { }");
}
// Parse all of them - parsers should never crash
for (const auto& input : inputs) {
auto result = parsePatternString(input);
// If we get here, parser didn't crash - good!
}
EXPECT_TRUE(true) << "Parser survived all " << inputs.size() << " inputs";
}