java-topology/defects/love2d/patch/love2d-0003-filesystem-allowed-mount-unordered-set.md

2.7 KiB

UNDF: UNDF-2026-000000456

love2d-0003: Filesystem::allowMountingForPath O(n) dedup each call — CWE-407

Severity: LOW File: src/modules/filesystem/physfs/Filesystem.cpp Function: Filesystem::allowMountingForPath() Line: 972

Description

allowMountingForPath() deduplicates an allowlist of mount paths using std::find on a std::vector<std::string> before every insert:

void Filesystem::allowMountingForPath(const std::string &path)
{
    if (std::find(allowedMountPaths.begin(), allowedMountPaths.end(), path) == allowedMountPaths.end())
        allowedMountPaths.push_back(path);   // O(n) scan every call — CWE-407
}

Each call is O(n) where n is the size of allowedMountPaths. The same path is also re-scanned twice in mount() (line 387) and unmount() (line 513), once each. With N paths allowed, N mount operations costs O(N²) total.

Fix

Replace allowedMountPaths vector with std::unordered_set<std::string>:

// FIX love2d-0003: unordered_set replaces O(n) vector scan — CWE-407
// In Filesystem.h, change:
//   std::vector<std::string> allowedMountPaths;
// to:
//   std::unordered_set<std::string> allowedMountPaths;

void Filesystem::allowMountingForPath(const std::string &path)
{
    allowedMountPaths.insert(path);  // O(1) amortized
}

// In mount():
auto it = allowedMountPaths.find(archive);   // O(1) was O(n)

// In unmount():
auto it = allowedMountPaths.find(archive);   // O(1) was O(n)
if (it != allowedMountPaths.end())
    return unmountFullPath(archive);

Patch

--- a/src/modules/filesystem/physfs/Filesystem.h
+++ b/src/modules/filesystem/physfs/Filesystem.h
@@ -34,6 +34,7 @@
+#include <unordered_set>
 #include <vector>
 #include <string>

-	std::vector<std::string> allowedMountPaths;
+	std::unordered_set<std::string> allowedMountPaths;   // FIX love2d-0003: O(1) lookup — CWE-407

--- a/src/modules/filesystem/physfs/Filesystem.cpp
+++ b/src/modules/filesystem/physfs/Filesystem.cpp
@@ -387,7 +387,7 @@ bool Filesystem::mount(const char *archive, const char *mountpoint, bool append
-	auto it = std::find(allowedMountPaths.begin(), allowedMountPaths.end(), archive);
+	auto it = allowedMountPaths.find(archive);    // O(1) was O(n)

@@ -513,7 +513,7 @@ bool Filesystem::unmount(const char *archive)
-	auto it = std::find(allowedMountPaths.begin(), allowedMountPaths.end(), archive);
+	auto it = allowedMountPaths.find(archive);    // O(1) was O(n)

@@ -970,7 +970,6 @@ void Filesystem::allowMountingForPath(const std::string &path)
-	if (std::find(allowedMountPaths.begin(), allowedMountPaths.end(), path) == allowedMountPaths.end())
-		allowedMountPaths.push_back(path);
+	allowedMountPaths.insert(path);               // O(1) amortized, set semantics