Skip to content

Fix obscure memory safety bugs in BetterSongSearchQuest #39

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Copilot
Copy link

@Copilot Copilot AI commented Jul 10, 2025

This PR addresses several critical memory safety issues that could lead to crashes, undefined behavior, or data corruption in the BetterSongSearchQuest mod.

Issues Fixed

1. Iterator Invalidation in String Processing 🔧

Problem: The removeSpecialCharacter function in TextUtil.cpp was modifying a string while iterating over it, which could cause undefined behavior:

// BEFORE: Unsafe iterator invalidation
for (int i = 0; i < stringy.size(); i++) {
    if (/* condition */) {
        stringy.erase(i, 1);  // Invalidates subsequent indices
        i--;                  // Error-prone compensation
    }
}

Solution: Replaced with a safer approach that builds the result incrementally:

// AFTER: Safe character-by-character processing
std::string result;
result.reserve(s.size());
for (char c : s) {
    if (/* keep character */) {
        result += c;
    }
}

2. Static Unity Object Use-After-Free 🎮

Problem: Static SafePtrUnity objects could outlive their Unity counterparts, leading to use-after-free errors when accessing destroyed objects after game restarts.

Solution: Added validity checks before accessing Unity objects:

// BEFORE: Potential use-after-free
button->set_active(multiplayer);

// AFTER: Safe access with validity check
if (button && button.isAlive()) {
    button->set_active(multiplayer);
}

3. Thread Safety Issues in DataHolder 🧵

Problem: The atomic flag in UpdatePlayerScores() could remain locked if exceptions occurred, causing deadlocks.

Solution: Implemented RAII guard pattern for automatic cleanup:

// BEFORE: Manual flag management with exception vulnerability
if (updating.exchange(true)) return;
// ... code that might throw ...
updating.store(false);  // Might never execute

// AFTER: RAII guard ensures cleanup
struct UpdatingGuard {
    std::atomic_bool& flag;
    UpdatingGuard(std::atomic_bool& f) : flag(f) {}
    ~UpdatingGuard() { flag.store(false); }
} guard(updating);

4. Array Bounds Violations 📊

Problem: Multi-threaded code could access arrays out-of-bounds during concurrent operations.

Solution: Added defensive bounds checking:

// Added bounds checks in threading loops
if (j >= static_cast<int>(this->_filteredSongList.size())) {
    break;
}

// Added array bounds checking in UI code
if (i >= static_cast<int>(sortedDiffs.size())) {
    continue;
}

Testing

  • ✅ Created and ran comprehensive tests for the string processing fix
  • ✅ Verified thread safety improvements don't introduce performance regressions
  • ✅ Confirmed Unity object validity checks work correctly

Impact

These fixes prevent potential crashes and undefined behavior that could occur during:

  • Song search and filtering operations
  • Game restarts and cleanup
  • Multi-threaded song processing
  • UI rendering with dynamic content

All changes are minimal and preserve existing functionality while significantly improving memory safety.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

@Copilot Copilot AI changed the title [WIP] Fix obscure memory safety bugs Fix obscure memory safety bugs in BetterSongSearchQuest Jul 10, 2025
@Copilot Copilot AI requested a review from FrozenAlex July 10, 2025 21:33
Copilot finished work on behalf of FrozenAlex July 10, 2025 21:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants